PostgreSQL declarative partitioning 的 attach / detach 操作注意

12次阅读

postgresql ATTACH PARTITION 要求子表严格匹配父表的CHECK/NOT NULL约束、分区键表达式及类型,INHERITS表需先NO INHERIT;DETACH仅解除关系不删数据但移除隐式CHECK;二者均需access EXCLUSIVE锁,阻塞写入,不支持在线执行。

PostgreSQL declarative partitioning 的 attach / detach 操作注意

attach 分区时主表约束必须完全匹配

PostgreSQL 要求 ATTACH PARTITION 的目标表(即待挂载的分区表)必须满足所有父表的约束条件,尤其是 CHECK 约束和 NOT NULL 约束。即使你用的是范围或列表分区,PostgreSQL 仍会显式检查子表的约束是否能被父表的分区键逻辑覆盖。

  • 如果子表有额外的 CHECK 约束(比如 CHECK (status = 'active')),而父表没有对应定义,ATTACH 会失败
  • 子表不能缺少父表中定义为 NOT NULL 的分区键列的 NOT NULL 约束
  • 使用 INHERITS 创建的旧式继承表不能直接 ATTACH,必须先 NO INHERIT 掉原继承关系

detach 操作不自动删除数据,但会断开约束依赖

DETACH PARTITION 只是解除父子关系,不会删数据、不改表结构、也不清索引。但要注意它会移除子表上由分区机制自动添加的隐式 CHECK 约束(例如 CHECK (created_at >= '2024-01-01' AND created_at )。

  • detach 后子表变成普通表,其数据不再受父表约束检查,查询父表时也不会包含它
  • 若子表仍有外键指向其他表,或被视图/函数引用,detach 仍可成功,但后续 DML 可能因约束缺失出错
  • detach 前建议手动备份该分区的 CHECK 定义,否则恢复 attach 时得重新推导边界

并发下 attach/detach 会持锁阻塞写入

这两个操作都需要在父表上获取 ACCESS EXCLUSIVE 锁,意味着:

  • 所有对父表的 INSERT/UPDATE/delete 会被阻塞,直到操作完成
  • 长事务或大分区(尤其带大量索引)会让锁持有时间显著增加
  • 不支持在线执行:无法在业务高峰期间静默完成;若需最小化影响,应选低峰期,并提前 VACUUM 目标分区以减少锁内扫描开销

分区键表达式变更后 attach 会失败

如果父表使用表达式分区(如 PARTITION BY RANGE (date_trunc('month', created_at))),那么待 attach 的子表必须:

  • 使用完全相同的表达式定义分区键,包括函数名、参数顺序、时区设置(如 date_trunc('month', created_at AT TIME ZONE 'UTC')... AT TIME ZONE 'Asia/Shanghai' 被视为不同)
  • 子表的分区键列类型必须与表达式结果类型严格一致(例如 date_trunc 返回 timestamp WITHOUT TIME ZONE,就不能用 TIMESTAMP WITH TIME ZONE 列直接映射)

这类不匹配通常报错:partition constraint is violated by some row,但实际原因常是表达式语义不等价,而非真有脏数据。

text=ZqhQzanResources