detach/attach比insert into...select更适合归档大表,因其是毫秒级元数据操作,不移动数据、不写wal、不阻塞dml;而后者需全量读写、日志膨胀、索引重建。

为什么 detach / attach 比 INSERT INTO ... SELECT 更适合归档大表
DETACH 和 ATTACH 是 PostgreSQL 分区表原生支持的元数据级操作,不移动实际数据文件,只修改系统目录记录。这意味着归档 1TB 的历史分区,耗时是毫秒级,而不是小时级。
-
INSERT INTO ... SELECT会触发全量数据读写、WAL 日志膨胀、索引重建,还可能阻塞后续 DML -
DETACH后的表变成普通堆表,可直接COPY到归档库或用pg_dump --table单独导出,不影响主业务表 - 注意:目标分区必须已存在且结构完全一致(包括约束、索引、存储参数),否则
ATTACH直接报错ERROR: partition constraint is violated by some row
detach 前必须验证的三件事
别急着执行 ALTER TABLE ... DETACH PARTITION,先确认:
- 分区是否为空?用
SELECT count(*) FROM partition_name检查,非空时需先VACUUM FULL或确认业务已停写 - 分区是否被任何外键引用?查
pg_constraint,有confrelid指向该分区则DETACH会失败 - 表空间是否独立?如果归档后要迁移到另一台机器,建议提前把历史分区建在单独
TABLESPACE,避免DETACH后还得手动搬数据文件
attach 回主表时最容易忽略的约束同步
ATTACH PARTITION 不自动继承主表的 CHECK 约束表达式,也不复制 NOT NULL 或生成列定义。常见翻车点:
- 主表有
CHECK (created_at ,但 detached 表没这个约束 → <code>ATTACH报错 - 用
pg_dump -t partition_name --no-owner --no-privileges导出后再恢复,容易漏掉ALTER TABLE ... ADD CONSTRAINT语句 - 正确做法:先在 detached 表上手动补全约束,再
ATTACH;或者用pg_dump --inserts --column-inserts导出带完整 DDL 的 SQL,重放前 grep 检查约束部分
归档后的分区表如何安全清理元数据残留
DETACH 成功后,分区仍存在于 pg_class 和 pg_inherits,只是断开了继承关系。若之后误删了该表,主表查询可能因缓存未刷新而短暂报错 relation does not exist。
- 执行
VACUUM pg_class和ANALYZE pg_inherits强制刷新系统表缓存 - 如果确定不再需要该分区,用
DROP TABLE IF EXISTS partition_name彻底删除,但务必确认备份已完成 - 生产环境建议加锁:在
BEGIN; LOCK TABLE parent_table IN SHARE UPDATE EXCLUSIVE MODE;下执行DETACH,防止并发 DDL 干扰
归档迁移真正的复杂点不在命令本身,而在 detach 前对业务写入状态的确认、attach 后对约束和统计信息的一致性校验——这些没法靠脚本全自动兜底,得人眼盯住。










