不能。ATTACH PARTITION是原子操作,持有ACCESS EXCLUSIVE锁,阻塞所有并发查询,读到的只能是完整前或完整后的状态,不存在中间态。
PostgreSQL 分区表 ATTACH PARTITION 期间能否读到不一致数据?
不能。只要用的是标准的 attach partition(非 concurrently),整个操作是原子的,且会持有一个 access exclusive 锁,阻塞所有并发查询直到完成。你不会看到中间态——因为根本不存在“中间态”:要么旧结构还在,要么新分区已就位。
但注意,这个结论只适用于 PostgreSQL 10+ 的原生声明式分区,且必须是 ATTACH,不是手动改 pg_inherits 或触发器模拟的伪分区。
-
ATTACH是 DDL,由事务系统保障原子性,失败则回滚,成功则立即对所有后续事务可见 - 锁级别高:会阻塞
SELECT、INSERT、UPDATE等一切访问该分区表的语句,直到命令返回 - 如果你在
ATTACH过程中发起SELECT,它会卡住,等锁释放后才执行——读到的永远是完整前或完整后的状态
想验证原子性,为什么不能只靠反复 SELECT?
因为锁机制让并发读天然串行化,你观察不到“撕裂”。真正能暴露问题的场景,是那些绕过锁、依赖底层对象状态的操作,比如:pg_class.relkind 查询、直接查 pg_inherits、或用 pg_stat_all_tables 观察统计信息刷新延迟。
- 在
ATTACH执行中,pg_class里新分区的relkind还是r(普通表),父表的relkind仍是p(分区表)——这些元数据变更和 DDL 原子绑定 - 但若你在事务内先
INSERT到子表,再ATTACH,而另一会话同时COPY到父表,就可能触发约束冲突(如check不匹配),这不是原子性破绽,而是逻辑校验时机问题 - 真正的风险点不在 DDL 本身,而在
ATTACH前没清理好子表数据(例如含超范围值),导致附加后查询报错,看起来像“中间态”,其实是校验失败
CREATE TABLE ... PARTITION OF 和 ATTACH 的原子性差异
两者都原子,但行为边界不同:PARTITION OF 是建表+挂载一步到位;ATTACH 是把已有表接入,需额外满足约束、索引、所有权等前提。
-
PARTITION OF创建的子表,其pg_inherits记录与表定义在同一个事务提交,无间隙 -
ATTACH要求子表已存在,且必须通过VALIDATE CONSTRAINT检查分区键约束——如果约束是NOT VALID,ATTACH会拒绝,除非加WITHOUT VALIDATION(此时不校验数据,但后续INSERT可能失败) - 性能上,
ATTACH几乎是瞬时的(只改元数据),而PARTITION OF含建表开销;但若子表很大,ATTACH后首次ANALYZE可能拖慢后续查询计划
测试时最容易被忽略的三个细节
多数人写个循环 SELECT COUNT(*) 就以为测了原子性,其实漏掉了关键路径。
- 没关自动提交:必须在显式事务里做
ATTACH,否则无法控制并发会话的观察窗口 - 忽略
pg_stat_activity:用SELECT state, query FROM pg_stat_activity WHERE query LIKE '%ATTACH%'查锁等待,比盲等SELECT返回更可靠 - 混淆“不可见”和“不一致”:分区未
ATTACH时,向父表INSERT会报错(no partition for partitioning key),这不是中间态,是设计使然;只有成功ATTACH后,INSERT才路由到新分区
真正要盯住的,是约束校验是否跳过、统计信息是否滞后、以及跨会话元数据查询的时间差——这些地方才有缝隙可测。










