为何PostgreSQL中带ONLY的ALTER TABLE修改默认值会锁表?
问题原因
当你使用ALTER TABLE ONLY修改列默认值时,PostgreSQL会强制获取ACCESS EXCLUSIVE锁——这是PostgreSQL中级别最高的表锁,会阻塞该表上的所有读写操作,所以你会感觉到"锁表"。
而不带ONLY的语句,在目标表没有子表的情况下,PostgreSQL会使用SHARE UPDATE EXCLUSIVE锁,这个锁级别更低,不会阻塞普通的SELECT、INSERT、UPDATE、DELETE操作,所以你观察不到锁表现象。
深层逻辑
虽然你的t_cats没有子表,但ONLY关键字会改变PostgreSQL的执行路径:
- 不带
ONLY时,PostgreSQL会先检查表是否有子表。如果没有,它会将修改默认值的操作视为轻量级元数据变更,使用低级别锁即可完成——因为修改默认值只需要更新系统表pg_attribute中的attdefault字段,不需要触碰实际的数据行。 - 带
ONLY时,PostgreSQL会进入"仅修改主表"的执行分支,这个分支会强制使用ACCESS EXCLUSIVE锁。哪怕当前没有子表,它也要确保在操作期间不会有新的子表被创建(防止出现主表和子表默认值不一致的情况),所以会持有最高级别的锁,导致其他操作被阻塞。
验证方式
你可以通过查询pg_locks视图确认两种语句的锁级别差异:
- 执行带
ONLY的语句时,在另一个会话查询:
SELECT mode FROM pg_locks WHERE relation = 't_cats'::regclass;
会返回AccessExclusiveLock。
- 执行不带
ONLY的语句时,同样查询会返回ShareUpdateExclusiveLock。
内容的提问来源于stack exchange,提问作者Ярослав Ведерников
相关产品推荐
相关产品推荐

