PostgreSQLのインデックス名などの長さ!

こんにちは、Anti-Pattern Inc.の塚本です。

PostgreSQLのインデックス名など識別子の長さについて調べたメモです。

usersテーブルに長いインデックス名を作成します。

CREATE UNIQUE INDEX unique_index_looooooooooooooooooooooooooooooooooong__users_name_email_key
  ON users (name, email) 
  WHERE deleted_at IS NULL;

成功しますが、”識別子が切り捨てられます”とメッセージがでます。

test_db=> CREATE UNIQUE INDEX unique_index_looooooooooooooooooooooooooooooooooong__users_name_email_key
test_db->   ON users (name, email) 
test_db->   WHERE deleted_at IS NULL;
NOTICE:  identifier "unique_index_looooooooooooooooooooooooooooooooooong__users_name_email_key" will be truncated to "unique_index_looooooooooooooooooooooooooooooooooong__users_name"
CREATE INDEX

統計情報コレクタ(pg_stat_user_indexes)で、今作成したインデックスを確認してみると、切り捨てられたインデックス名で作成されてます。

  test_db=> select * from pg_stat_user_indexes where indexrelname = 'unique_index_looooooooooooooooooooooooooooooooooong__users_name';
  -[ RECORD 1 ]-+--------------------------------------------------------
  relid         | 16528
  indexrelid    | 4934005
  schemaname    | engineed
  relname       | users
  indexrelname  | unique_index_looooooooooooooooooooooooooooooooooong__users_name
  idx_scan      | 0
  idx_tup_read  | 0
  idx_tup_fetch | 0

indexrelnameのtypeがnameとなっているのが分かります

  test_db=> \d+ pg_stat_user_indexes
                       View "pg_catalog.pg_stat_user_indexes"
      Column     |  Type  | Collation | Nullable | Default | Storage | Description 
  ---------------+--------+-----------+----------+---------+---------+---
   relid         | oid    |           |          |         | plain   | 
   indexrelid    | oid    |           |          |         | plain   | 
   schemaname    | name   |           |          |         | plain   | 
   relname       | name   |           |          |         | plain   | 
   indexrelname  | name   |           |          |         | plain   | 
   idx_scan      | bigint |           |          |         | plain   | 
   idx_tup_read  | bigint |           |          |         | plain   | 
   idx_tup_fetch | bigint |           |          |         | plain   | 
-抜粋- 

pg_typeカタログでデータ型の情報がわかるので、nameを確認すると、typlenが64になってます。

https://www.postgresql.jp/document/12/html/catalog-pg-type.html

  test_db=> select * from pg_type where typname = 'name';
  -[ RECORD 1 ]--+---------
  typname        | name
  typnamespace   | 11
  typowner       | 10
  typlen         | 64
  typbyval       | f
  typtype        | b
-抜粋-

PostgreSQLマニュアル "4.1.1. 識別子とキーワード"

システムはNAMEDATALEN-1バイトより長い識別子を使いません。 より長い名前をコマンドで書くことはできますが、短く切られてしまいます。 デフォルトではNAMEDATALENは64なので、識別子は最長で63バイトです。 この制限が問題になる場合は、src/include/pg_config_manual.h内のNAMEDATALEN定数の値を変更して増やすことができます。

https://www.postgresql.jp/document/12/html/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS

PostgreSQLマニュアル "19.15. 設定済みのオプション"

max_identifier_length (integer)
最長の識別子の長さを報告します。 サーバ構築時のNAMEDATALENの値より一つ少なく設定されます。 デフォルトのNAMEDATALENの値は64ですので、デフォルトのmax_identifier_lengthは63バイトで、マルチバイト符号化方式を使用している場合、63文字以下になることがあります。

https://www.postgresql.jp/document/12/html/runtime-config-preset.html

NAMEDATALEN定数を変えてリコンパイルすると、pg_typeのnameレコードのtyplenが変更できそうです。

事の発端は、外部参照キー名称をこのように付けてました。(正確にはツールで自動生成してました)
"FK" + "_" + 外部参照するテーブル名 + "_" + "TO" + "_" + 自テーブル名
インデックス名はこんな感じです。
テーブル名 + "_" + カラム名 + "_" + "key"

設計中のテーブル名が長いため、設定したインデックス名、外部参照キー名が切り捨てられていることに気づき・・・。

nameという型を知ったので、勉強になった点はよかった!!

でも長いテーブル名はどうしようかな・・・見直そうかな。