ON DELETE NO ACTION
が定義されている既存の外部キーがあります。この外部キーをON DELETE CASCADE
に変更する必要があります。トランザクション内でこれを行うことができます:
begin;
alter table posts drop constraint posts_blog_id_fkey;
alter table posts add constraint posts_blog_id_fkey foreign key (blog_id) references blogs (id) on update no action on delete cascade;
commit;
問題は、posts
テーブルが大きい(400万行)ことです。これは、外部キーの検証にかなりの時間がかかることを意味します(データベースのコピーでこれをテストしました)。外部キーの削除/追加 posts
でACCESS EXCLUSIVE
ロックを取得 。したがって、制約の検証が行われている間ロックが保持されるため、外部キーブロックallへの適切な時間のposts
テーブルへのアクセスを追加します。オンライン移行を実行する必要があります(専用のダウンタイムウィンドウはありません)。
私は2トランザクションを実行して、チェックに時間がかかることを支援できることを知っています。
begin;
alter table posts drop constraint posts_blog_id_fkey;
alter table posts add constraint posts_blog_id_fkey foreign key (blog_id) references blogs (id) on update no action on delete cascade not valid;
commit;
begin;
alter table posts validate constraint posts;
commit;
このアプローチの利点は、ACCESS EXCLUSIVE
ロックが非常に短時間保持され、制約を削除/追加してから、制約のみを検証することです a SHARE UPDATE EXCLUSIVE
on posts
およびROW SHARE
lock on blogs
私はPostgres 9.5を使用しているため。
これには欠点がありますか? NOT VALID
を制約に追加すると、既存データは検証されませんが、VALIDATE CONSTRAINT
willの前に挿入/更新された行はチェックされます。外部キーが同じトランザクションで削除/追加されるため、一貫性のないデータが作成される可能性はありますか?
ドキュメントはこれについて NOT VALID
について述べています
ADD table_constraint [ NOT VALID ]
このフォームは、
CREATE TABLE
、と同じ構文を使用して、テーブルに新しい制約を追加します。オプションNOT VALID
は、現在、外部キーとCHECK制約でのみ許可されています。制約にNOT VALID
のマークが付けられている場合、テーブル内のすべての行が制約を満たすことを確認するために時間がかかる可能性のある初期チェックがスキップされます。制約は引き続き後続の挿入または更新に対して適用されます(つまり、外部キーの場合、参照されるテーブルに一致する行がない限り失敗します。新しい行が指定されたチェックと一致しない限り、失敗します。制約)。ただし、データベースは、VALIDATE CONSTRAINT
オプションを使用して検証されるまで、制約がテーブル内のすべての行に対して保持されるとは想定しません。
あなたの懸念、
NOT VALID
を制約に追加すると、既存のデータは検証されませんが、VALIDATE CONSTRAINT
の前に挿入/更新された行はチェックされます。
それらは検証中にのみチェックされます[〜#〜] [〜#〜]検証後にそれを伝えたので、ダウンタイムをスケジュールするまでそれを遅らせることができます。
外部キーが同じトランザクションで削除/追加されるため、一貫性のないデータが作成される可能性はありますか?
いいえ、2番目にNOT VALID
を追加するので、挿入されたすべての行に適用されます[〜#〜] [〜#〜]ステートメントの後に常にあるかのように。 VALIDATIONは、参照される行が存在しない場合にFOREIGN KEY
の作成を拒否するためのものです。カスケードとは何もしない、観察する
CREATE TABLE foo
AS
SELECT 1 AS a;
CREATE TABLE bar
AS
SELECT a
FROM ( VALUES (1),(2) )
AS t(a);
ALTER TABLE foo
ADD PRIMARY KEY (a);
ALTER TABLE bar
ADD FOREIGN KEY (a)
REFERENCES foo
ON DELETE CASCADE
NOT VALID;
DELETE FROM foo;
TABLE foo;
a
---
(0 rows)
test=# TABLE bar;
a
---
2
(1 row)
この時点で、あなたは見ることができます
bar
からbar
にカスケードされた削除(以下に示すように)制約はまだ検証できませんが、カスケード削除の目的では、すべてが適切です。
ALTER TABLE bar VALIDATE CONSTRAINT bar_a_fkey ;
ERROR: insert or update on table "bar" violates foreign key constraint "bar_a_fkey"
DETAIL: Key (a)=(2) is not present in table "foo".
ところであなたはこれを書くことができます
begin;
alter table posts drop constraint posts_blog_id_fkey;
alter table posts add constraint posts_blog_id_fkey foreign key (blog_id) references blogs (id) on update no action on delete cascade not valid;
commit;
このような
alter table posts
drop constraint posts_blog_id_fkey,
add constraint posts_blog_id_fkey
foreign key (blog_id)
references blogs (id)
on update no action
on delete cascade
not valid;
Txnでラップする必要はありません。また、txnで単一のステートメントをラップする必要はありません-PostgreSQLはMySQLではありません。すべてがすでにトランザクションに対応しています。