Skip to content

Commit 5bcbfb4

Browse files
author
xiongcc
committed
添加第69章:How to add a CHECK constraint without downtime
1 parent 6a009d4 commit 5bcbfb4

File tree

1 file changed

+48
-0
lines changed

1 file changed

+48
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# How to add a CHECK constraint without downtime
2+
3+
>我每天都会发布一篇新的 PostgreSQL "howto" 文章。加入我的旅程吧 — 订阅、提供反馈、分享!
4+
5+
添加 `CHECK` 约束有益于:
6+
7+
- 提升数据质量
8+
- 在 PG12+ 中,定义 `NOT NULL` 约束不需要停机 (更多信息参考[此处](https://gitlab.com/postgres-ai/postgresql-consulting/postgres-howtos/-/blob/main/0060_how_to_add_a_column.md?ref_type=heads#not-null))
9+
10+
要在不中断服务的情况下添加 `CHECK` 约束,我们需要:
11+
12+
1. 快速定义带有 `NOT VALID` 标志的约束
13+
2. 在一个单独的事务中,"验证"现有行是否满足该约束
14+
15+
## 使用NOT VALID添加CHECK约束
16+
17+
示例:
18+
19+
```sql
20+
alter table t
21+
add constraint c_id_is_positive
22+
check (id > 0) not valid;
23+
```
24+
25+
这仅需要一个非常短暂的 `AccessExclusiveLock`,因此在负载较大的系统上,应设置较低的 `lock_timeout` 并进行重试 (参考:[Zero-downtime Postgres schema migrations need this: lock_timeout and retries](https://postgres.ai/blog/20210923-zero-downtime-postgres-schema-migrations-lock-timeout-and-retries))。
26+
27+
🖋️ **重要**:当 `NOT VALID `约束添加之后,新的数据写入会立即进行检查 (而旧数据尚未验证,可能会违反约束):
28+
29+
```sql
30+
nik=# insert into t select -1;
31+
ERROR: new row for relation "t" violates check constraint "c_id_is_positive"
32+
DETAIL: Failing row contains (-1).
33+
```
34+
35+
## 验证
36+
37+
完成添加约束的过程后,我们需要验证旧数据:
38+
39+
```sql
40+
alter table t
41+
validate constraint c_id_is_positive;
42+
```
43+
44+
该操作会扫描整个表,因此对于大表可能需要较长时间 — 但此查询仅获取表上的 `ShareUpdateExclusiveLock`,不会阻塞运行 DML 查询的会话。但是,如果有 `autovacuum` 在预防事务 ID 回卷的模式下运行并处理该表,或有其他会话在该表上创建索引或执行其他 `ALTER` 操作,则锁请求会被阻塞。因此,在运行 `ALTER` 之前,应确保没有这些繁重的操作在执行,以避免过长的等待时间。
45+
46+
## 我感
47+
48+
这个技巧很不错,在创建分区表的时候也可以使用这个技巧,直接 alter table xxx add constraint 会全程 8 级锁,可以先 not valid,再慢慢校验,最后 attach。

0 commit comments

Comments
 (0)