PostgreSQLの文字列型の最大長は?

(更新日: 2018/08/13)

PostgreSQLには

  • varchar(n) 型
  • char(n) 型
  • text型

の文字列型があります。他にバイナリも保存できる

  • bytea型

もあります。

text/byteaの最大サイズは1GiBだ、と私も思っていたのですが違いました。

varchar/char型

PostgreSQL 10で試したところ

  • 100Ki”文字”まで

保存できます。”文字”なので文字エンコーディングと文字によって使用されるバイト数は変わってきます。UTF-8なら凡そ300KiBです。1

マニュアルにも記載されていますが、実際のストレージとしては最大約1GiB保存できる、としてあります。しかし、100Ki文字より大きな値を設定するとCREATE TABLE時にエラーになります。

text型

同じくPostgreSQL 10で試したところ

  • 1GiB – 53 byteまで

保存できました。以前のマニュアルには1GiBまで保存可能との記載があったように思います。現在のマニュアルにはtext型を含め、最大値の記載が無い(?)ようです。

bytea型

同じくPostgreSQL 10で試しまた。bytea型は1GiBくらいまで保存できるハズですが、半分くらいしか保存できませんでした。

PHP 7.2を使ってテストしています。

512MiB – 9 byte までしか保存できません。これ以上にすると

PHP Warning: pg_query_params(): Query failed: ERROR: out of memory
DETAIL: Cannot enlarge string buffer containing 0 bytes by 1073741824 more bytes.
Query Failed: INSERT INTO mytable (b) VALUES ($1)

とエラーになります。念の為、PHPのエラーメッセージで無いことを確認するため

Cannot enlarge string buffer containing

をPHPのソースディレクトリから

を実行しましたが、定義されていませんでした。

PostgreSQL文字列型のデータ最大長制限の理由

Facebookで「こんな動作になっている」と書いたら、こんな仕様になっている、とコメントを頂きました。

これはTOASTが導入された際の仕様として、pallocする際にデータの最大値を制限していることが原因のようです。2

今のPostgreSQLのプリペアードクエリはbytea型のカラムに対して、エスケープ無しでも挿入できます。この場合、text型と同じ1GiB – 53 byteまで保存できます。

プリペアードクエリがエミュレートされているライブラリ(パラメーターがエスケープされるライブラリ)では、バイナリ値はPQescapeBytea/PQescapeByteaConnでエスケープしなければなりません。これらのエスケープ関数はHEX形式と古いOCTAL形式の2種類があり、これらを使う環境では約1GiBのバイナリデータは保存できません。半分以下になります。

大きなバイナリデータを取り扱う場合には注意が必要です。

まとめ

リソースは有限です。どんな物でも最大限/最小限の限界があります。限界がメモリ量やディスク容量依存の場合もありますが、限界があることには変りありません。

ライブラリなどの場合、「使えるところまで使う」でも構いません。しかし、アプリケーションの場合は「ここまでは使える」という制限を設定しておく方が良いです。

こういった制限は

  • 先ずは入力データバリデーションで制限以内であることを保証する
  • ロジックのバリデーション/エラー処理でビジネスルールとの適合性を検証する
  • フェイルセーフ対策として、実際に使う場合に制限以内であることをバリデーションする

といった多層防御で護る必要があります。アプリの場合、「フェイルセーフ対策だけに頼る」のは脆弱な作り方になります。

バリデーションには3種類のバリデーションがある 〜 セキュアなアプリケーションの構造 〜

 


  1. UTF-8の一文字は1バイトから4バイトまでの可変長です。 
  2. ここはソースで確認していないですが、海外さんが仰るの間違いないでしょう。 
Facebook Comments
Pocket