The*_*Sky 9 postgresql foreign-key postgresql-9.5 online-operations
我有一个已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;
Run Code Online (Sandbox Code Playgroud)
问题是该posts表很大(400 万行),这意味着验证外键可能需要很长的时间(我已经用数据库的副本对此进行了测试)。滴/添加外键获取的ACCESS EXCLUSIVE锁上posts。因此,添加外键会在相当长的时间内阻止对表的所有访问,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;
Run Code Online (Sandbox Code Playgroud)
这种方法的优点是ACCESS EXCLUSIVE锁被维持了很短的时间下降/加约束,然后验证约束只有一个SHARE UPDATE EXCLUSIVE上posts和ROW SHARE上锁定blogs,因为我对Postgres的9.5。
这有什么缺点吗?我知道添加NOT VALID到约束意味着不验证现有数据,但VALIDATE CONSTRAINT 将检查之前插入/更新的任何行。因为在同一个事务中删除/添加外键,是否有可能创建不一致的数据?
文档是这样说的 NOT VALID
Run Code Online (Sandbox Code Playgroud)ADD table_constraint [ NOT VALID ]这种形式使用与 相同的语法向表添加一个新约束
CREATE TABLE,加上选项NOT VALID,目前仅允许用于外键和 CHECK 约束。如果约束被标记为NOT VALID,则跳过可能冗长的初始检查以验证表中的所有行是否满足约束。该约束仍将针对后续插入或更新强制执行(也就是说,除非引用表中有匹配的行,否则它们将失败,在外键的情况下;除非新行与指定的检查匹配,否则它们将失败约束)。但是数据库不会假设约束对表中的所有行都成立,直到使用该VALIDATE CONSTRAINT选项对其进行验证。
你所关心的,
我知道添加
NOT VALID到约束意味着不验证现有数据,但VALIDATE CONSTRAINT将检查之前插入/更新的任何行。
他们只会在验证过程中进行检查后你告诉它来验证,所以您需要推迟,直到你预定的停机时间。
因为在同一个事务中删除/添加外键,是否有可能创建不一致的数据?
不,因为您添加的第二个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)
Run Code Online (Sandbox Code Playgroud)
此时你可以看到
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".
Run Code Online (Sandbox Code Playgroud)
顺便说一句你可以写这个
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;
Run Code Online (Sandbox Code Playgroud)
像这样
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;
Run Code Online (Sandbox Code Playgroud)
您不必将其包装在 txn 中。您也不必在 txn 中包装任何单个语句——PostgreSQL 不是 MySQL。一切都已经是事务性的。
| 归档时间: |
|
| 查看次数: |
12370 次 |
| 最近记录: |