PostgreSQL在线DDL
PostgreSQL在线DDL
目录
PostgreSQL 的“在线 DDL”并没有像 MySQL 5.6 之后那样“一键 ONLINE”的语法,而是“有的语句天然不阻塞业务,有的语句需要借助技巧或第三方工具才能做到零停机”。下面把生产环境常用的做法一次性梳理给你,按“无需工具 → 需要工具 → 无法在线只能停机”三个层次归纳:
1️.无需第三方工具即可“在线”执行的 DDL
(对业务读写几乎无阻塞)
| 操作 | 语法示例 | 注意事项 |
|---|---|---|
| 添加可空字段 | ALTER TABLE t ADD COLUMN c1 int; |
只要不给默认值、不设 NOT NULL,就只需在系统目录加一条记录,瞬间完成。 |
| 添加默认值且可空 | ALTER TABLE t ADD COLUMN c2 int DEFAULT 0; |
9.4+ 版本已优化:会先把默认值放到系统目录,不立即改每一行,查询时动态填充,因此同样秒级完成。 |
| 删除字段 | ALTER TABLE t DROP COLUMN c1; |
仅标记“已删除”,不会立即清理数据,不会长时间锁表。 |
| 创建/删除普通索引 | CREATE INDEX CONCURRENTLY idx ON t(c1);DROP INDEX CONCURRENTLY idx; |
必须带 CONCURRENTLY 关键字,否则会锁表;不能放在显式事务里。 |
| 创建/删除 UNIQUE / PK 索引 | CREATE UNIQUE INDEX CONCURRENTLY idx ON t(c1); |
同上,但需保证无重复值。 |
| 重命名表 / 列 / 索引 | ALTER TABLE t RENAME TO new_t; |
只改元数据,瞬间完成。 |
2.需要借助技巧或第三方工具才能“在线”执行的 DDL
(业务可读写,但过程较长,需要 DBA 干预)
| 操作 | 推荐做法 | 关键点 |
|---|---|---|
| 改列数据类型 (int → bigint、varchar(32)→varchar(64) 等) |
1. 加影子列 2. 双写触发器 3. 分批回填数据 4. 切换主键/索引 5. 删除旧列 |
阿里云、GitHub、Instagram 都用过该套路;可写成脚本自动化。 |
| 添加带 NOT NULL 的列 | 先加可空列 → 填数据 → 再 ALTER SET NOT NULL;或参考上一条影子列方案。 | 直接 ADD COLUMN ... NOT NULL DEFAULT xxx 会重写全表并长时间锁表。 |
| 变更主键 | 影子列 + CREATE UNIQUE INDEX CONCURRENTLY + 交换主键。 |
切换时需要在极短窗口拿 ACCESS EXCLUSIVE 锁,业务几乎无感知。 |
| 分区 / 合并分区 | PostgreSQL 11+ 的 DETACH/ATTACH PARTITION 已大幅降低锁时间,但仍需要短暂锁;超大表可结合逻辑复制或触发器影子表方案。 |
|
| 一键式工具 | • pg-osc(Ruby 版,类似 gh-ost) • pg_repack(C 版,支持重建表、索引) • pt-osc 思路的 postgres_online_schema_change |
工具内部做“影子表 + 触发器 + 交换”流程,官方文档会给出磁盘空间、主键、外键等限制。 |
3.目前仍无法在线完成,必须停机或接受长锁的 DDL
(需要业务低峰期或维护窗口)
| 操作 | 原因 |
|---|---|
| 减小列长度(varchar(64)→varchar(32)) | 需要检查已有数据是否超长,必须重写表。 |
| 修改列顺序 | 系统列位置固定,只能通过重写表实现。 |
| 删除被外键引用的列 | 需同时更新引用端,锁级联。 |
| 改列为 NOT NULL 且无默认值 | 需要全表扫描验证 NULL,锁时间长。 |
实战小结(DBA 常用 checklist)
- 先跑 \d+ 表名 或 pg_stat_activity 确认当前无长事务。
- 能用 CONCURRENTLY 就用;不能用的先评估数据量。
- 超 1 亿行的大表改结构,优先考虑 pg-osc 或 影子列 + 触发器 方案。
- 任何 DDL 前先在测试库跑一遍,记录耗时、锁等待、磁盘空间。
- 预留至少 1.5 倍表大小的磁盘空间做影子表 / 临时索引。
一句话总结:
PostgreSQL 的“在线 DDL”没有统一开关,而是“语法特性 + 手工影子表 + 第三方工具”的组合拳;日常 80% 需求可以用 ADD COLUMN 可空、CREATE INDEX CONCURRENTLY 解决,剩余 20% 用 pg-osc 或 影子列脚本 基本都能做到零停机。

浙公网安备 33010602011771号