PostgreSQL 6 min read

PostgreSQLのtext型 ― varchar(n)・char(n)との違いと長さの上限

PostgreSQL の text は、長さの制限が無い文字列型です。MySQL の TEXT 型のように 65,535 バイトといった上限はありません。この記事の出力は PostgreSQL 17.6 で採りました。

まず見る(結論)

  • text と varchar(n) は、長さの検査があるかどうかだけが違う。性能は同じ
  • 格納できる最大は約 1GB(公式ドキュメント)
  • varchar(n) の n は文字数。日本語も1文字は1と数える
  • char(n) は空白で埋められ、比較や連結で空白が消える。特別な理由が無ければ使わない

3つの型の違い

公式ドキュメントには、3つの型の間に性能差は無く、空白埋めのある char(n) はむしろ少し遅いと書かれています。

表 t_txt(t text, v varchar(5), c char(5)) で確かめました。

varchar(n) を超えるとエラー、n は文字数

INSERT INTO t_txt(v) VALUES ('abcdef');
ERROR:  value too long for type character varying(5)

INSERT INTO t_txt(v) VALUES ('abcde');        -- 通る
INSERT INTO t_txt(v) VALUES ('あいうえお');   -- 通る

SELECT v, length(v), octet_length(v) FROM t_txt;
     v      | length | octet_length
------------+--------+--------------
 abcde      |      5 |            5
 あいうえお |      5 |           15

length が文字数、octet_length がバイト数です。

エラーにならず切り詰められる場合が2つある

超えた分が空白だけなら、エラーにならず、空白が削られて入ります。'abc '(6文字)を入れると、'abc '(5文字)になりました。

明示的にキャストしたときも、エラーではなく切り捨てです。

SELECT 'abcdefg'::varchar(5) AS cast_result;
 cast_result
-------------
 abcde

アプリケーション側でキャストしてから入れている処理があると、データが欠けても気づけません。

char(n) は空白で埋められる

INSERT INTO t_txt(c) VALUES ('ab');
SELECT c, length(c), octet_length(c), c = 'ab' AS eq_ab, c || '|' AS concat_bar FROM t_txt;
   c   | length | octet_length | eq_ab | concat_bar
-------+--------+--------------+-------+------------
 ab    |      2 |            5 | t     | ab|

末尾の空白に意味があるデータでは、入れた値と取り出した値が一致しません。

長い文字列と保存サイズ

text の列に 10万文字の repeat('x', 100000) を入れると、length は 100000、pg_column_size は 1156 バイトでした。一定の大きさを超えた値は自動で圧縮され、さらに大きければ表の外(TOAST)に置かれます。同じ文字の繰り返しなので、ここまで小さくなっています。

短い値のサイズは text と varchar(n) で同じです。

SELECT pg_column_size('abc'::text) AS size_text,
       pg_column_size('abc'::varchar(10)) AS size_varchar10,
       pg_column_size('abc'::char(10)) AS size_char10;
 size_text | size_varchar10 | size_char10
-----------+----------------+-------------
         7 |              7 |          14

char(10) は空白で10文字に埋めるので、その分大きくなります。

型を変える

varchar(n) から text へは、そのまま変えられます。

ALTER TABLE t_txt ALTER COLUMN v TYPE text;
ALTER TABLE

短くする方向は、入っている値が収まらなければ失敗します。

ALTER TABLE t_txt ALTER COLUMN v TYPE varchar(3);
ERROR:  value too long for type character varying(3)

上限を決めにくい列は text にしておき、長さを制限したくなったら CHECK (char_length(列) <= 100) の制約を足す方法もあります。制約なら、型を変えずに付け外しできます。