web-dev-qa-db-ja.com

テーブルスキャン中にテーブルをロックせずに列をNOT NULLに設定するにはどうすればよいですか?

(以前の質問は:Postgresはnullでない複数の列を設定するときに複数列のインデックスを使用しますか?)


通常、null以外の列を設定する場合、インデックスがない場合は最初に追加します。これにより、postgresが(うまくいけば)テーブルのロック中にテーブルスキャンを実行しているときにインデックスを使用して、テーブルがロックされるようにすることができます。短時間で。

次のように、nullではないいくつかの列を設定したい:

alter table foos
  alter column bar1 set not null
  alter column bar2 set not null
  alter column bar3 set not null
  alter column bar4 set not null;

これらの列に複数列のインデックスを作成した場合、この変更を行う前にロックされたテーブルをスキャンするときにpostgresはそれを使用しますか?

CREATE INDEX CONCURRENTLY my_index on foos (bar1, bar2, bar3, bar4);

IS NULL(またはIS NOT NULL)で部分インデックスを作成した場合

CREATE INDEX CONCURRENTLY my_index on foos (bar1, bar2, bar3, bar4) where bar1 is null and bar2 is null and bar3 is null and bar4 is null;
4
John Bachir

別のpostgresql貢献者からの別の回答。

PostgreSQLは、「alter table set not null」の実行中にインデックスを使用しようとはしません。実装されていません。

インデックススキャンの適切な実装は難しい部分です。このクエリのようなことはできません

select exists(select from foos where bar1 is null)

テーブル変更コマンドから さまざまな理由で 。このような機能を使用するには、限られたユースケースでのみ、大きなコード(およびおそらく、一部のEdgeケースでは壊れやすいコード)、多くの作業が必要になります。開発者が気に入らないもの。実際、pgsql-hackersコミュニティは、NOT NULLがシステムカタログにどのように格納されるかを好みません。カタログのこの部分を再設計すると、きれいになります。その後、短いロックでSET NOT NULL NOT VALIDを実行し、排他ロックなしでテーブルの検証を行うことができます。に似ている alter table .. add constraint ... not valid + alter table .. validate constraint(チェック制約または外部キー)。しかし、そのような再設計ははるかに手間がかかり、やりたい人は誰もいません。

しかし、良いニュースがあります。PostgreSQL12以降では、テーブル全体をスキャンすることだけが選択肢ではありません。 alter table set not nullは、既存のチェック制約によってNOT NULLの正当性を証明できます。したがって、次のことができます。

-- short-time exclusive lock
alter table foos 
  add constraint foos_not_null 
  check (bar1 is not null) not valid;

-- seqscan, but without exclusive lock, concurrent sessions can read/write
alter table foos validate constraint foos_not_null;

-- exclusive lock, but foos_not_null proves: there is no NULL in this column
-- so this alter table would be fast
alter table foos alter column bar1 set not null;
-- not needed anymore
alter table foos drop constraint foos_not_null;

それは my patch でした。ええ、これは回避策のように見えます。しかし、幸いにも、それはマージされ、今ではset not null長い排他ロックなし。

5
Melkij

私はソースコード(src/backend/commands/tablecmds.cの関数ATRewriteTable)を調べましたが、PostgreSQLは常にテーブルの順次スキャンを使用してNOT NULL制約を検証します。

したがって、インデックスを作成しても実行速度は向上しません。

3
Laurenz Albe