web-dev-qa-db-ja.com

varchar()の長さ制限(type-modifier)を変更すると、テーブルまたはインデックスが書き換えられますか?

この質問 に続いて、varchar()の長さ制限(type-modifier)を変更すると、テーブルの書き換えまたはCHECK制約?その質問から、あなたはそれを見ることができます Brandurによる主張

長さを変更したい場合は、_ALTER TABLE_に排他ロックが必要です( https://www.postgresql.org/docs/current/static/sql-altertable.html …を参照)。 。 CHECKの変更は瞬時に行われます。質問テキストを呼び出した質問に答えるときCHECK (char_length(email) <= 255) vs varchar(255)

これはDepeszの投稿、2010年からの投稿で発生したようです "CHAR(X)VS. VARCHAR(X)VS. VARCHAR VS. TEXT – UPDATED 2010-03-03 "

では、[varcharを使用して]制限を大きくするとどうなりますか?

PostgreSQLはテーブルを書き換える必要があります。これには2つの非常に重要な欠点があります。1.操作時にテーブルの排他ロックが必要です2.重要なテーブルの場合、かなりの時間がかかります

これはコメントでもう一度見ることができます here(2017)

それでも、VARCHAR(50)VARCHAR(250)に変換する場合、可能なテーブルロックに対するすべてのINSERTでサブミリ秒の差分をとります。

そして再び here(2012)

余談ですが、回避できる場合は特にvarcharを使用しません。特に、長さ修飾子を使用しない場合です。タイプ・テキストが実行できなかったことはほとんどありません。長さの制限が必要な場合は、テーブル全体を書き換えることなく変更できる列制約を使用します。

そして明らかに 主張を疑っている他の人たち

この単一の主張に対処するだけの価値があるかもしれません。

4
Evan Carroll

基本的に、これは古い情報です。 9.2以降は関係ありません。さて、私が見ることができる唯一の欠点は、長さの制約がより制限的になり、再チェックする必要がある場合、インデックスが書き直されることです。

Erwinによって発見された9.1のリリースノートには、

適切な場合にALTER TABLE ... SET DATA TYPEがテーブルの書き換えを回避できるようにしました(Noah Misch、Robert Haas)

たとえば、varchar列をテキストに変換する場合に、テーブルを書き換える必要がなくなりました。ただし、varchar列の長さの制約を増やすには、テーブルの書き換えが必要です。

9.2のリリースノート 、@ a_horse_with_no_nameが発見したように、

特定のALTER TABLE ... ALTER COLUMN TYPE操作のテーブルとインデックスを再構築する必要性を低減しました(Noah Misch)

Varchar列またはvarbit列の長さ制限を増やしたり、制限を完全に削除したりしても、テーブルを書き換える必要はなくなりました。同様に、数値列の許容精度を上げたり、列を制約付き数値から制約なし数値に変更したりしても、テーブルを書き換える必要はありません。間隔、タイムスタンプ、タイムスタンプのタイプを含む同様のケースでは、テーブルの書き換えも回避されます。

ALTER のドキュメントには、

DEFAULT句を使用して列を追加するか、既存の列のタイプを変更するには、テーブル全体とそのインデックスを書き換える必要があります。 既存の列のタイプを変更するときの例外として、USING句が列の内容を変更せず、古いタイプが新しいタイプにバイナリ強制可能か、新しいタイプに対する制約のないドメインでは、テーブルの書き換えは必要ありません。ただし、影響を受ける列のインデックスは再構築する必要があります。システムOID列を追加または削除する場合も、テーブル全体を書き換える必要があります。 大きなテーブルでは、テーブルやインデックスの再構築にかなりの時間がかかる場合があります。一時的に2倍のディスク容量が必要になります

私が変更したa_horse_with_no_nameが提供するテストケースに続いて、これを実際に見てみましょう。

\timing 1

CREATE TABLE alter_test (id int primary key, some_data varchar(50));
INSERT INTO alter_test
  SELECT i, md5(i::text)
  FROM generate_series(1,1e7) AS gs(i);

ALTER TABLE alter_test
  ALTER COLUMN some_data
  TYPE varchar(55);
Time: 5.671 ms

したがって、インデックスがなければ速度が低下することはありません。次に、インデックスを追加して、もう一度試します。

CREATE INDEX ON alter_test (some_data);
ALTER TABLE alter_test
  ALTER COLUMN some_data
  TYPE varchar(55);
Time: 6.423 ms

テーブルでVACUUM FULL ANALYZEを試してvarcharの長さをもう一度長くしましたが、それでも時間がかかりませんでした。すべてのケースでそれが適切であるとは言わないが、少なくとも単純なケースでは、インデックスが付けられていても、制約の制限を緩和するのであれば、これは問題ではないようです。ただし、長さの制約をより制限的にすることは、何かをしているようです。

ALTER TABLE alter_test
  ALTER COLUMN some_data
  TYPE varchar(50);
ALTER TABLE
Time: 59690.885 ms

インデックスを削除して再試行すると、かなり高速になり、

DROP INDEX alter_test_some_data_idx ;
DROP INDEX
Time: 85.978 ms
test=# ALTER TABLE alter_test
  ALTER COLUMN some_data
  TYPE varchar(49);
ALTER TABLE
Time: 9297.271 ms

したがって、長さの制約がより制限的になり、再検証する必要がある場合にのみ、インデックスが書き換えられます。

8
Evan Carroll