截断一个表被另一个表阻止

时间:2015-02-26 18:34:08

标签: postgresql

Postgres 9.4,Ubuntu 10

我一直无法在这里找到这个确切的问题,所以在这里:

对于我数据库中的每个表t,我有一个表t_audit。表t上的每次删除,插入和更新都会触发一个将记录插入表t_audit的函数。

每晚,一个进程会截断每个t_audit表。

昨晚,表t上的select会阻止t_audit上的截断继续进行。我当时没有保存pg_stat_activity中的内容,但我确实保存了blocking_locks()的输出。

  1. 阻止pid:RowExclusiveLock,t,选择* from t where ......,
  2. 等待pid:AccessExclusiveLock,t_audit,truncate table t_audit,
  3. 我不确定为什么t上的select会阻塞t_audit上的截断。因为我没有保存pg_stat_activity,所以我可以假设最好的选择是“在事务中空闲”。我问当时正在运行查询的人,他说他没有在事务中运行更新。他确实在选择之前更新了表格t。他没有关闭他的连接,因为pid仍然有效,直到我在pid上运行了pg_terminate_backend。

    之前有没有人遇到过这个问题?除了在调用truncate之前在“事务中空闲”的任何pid上运行pg_terminate_backend之外,是否有推荐的过程?

    感谢您阅读并花时间回复。

1 个答案:

答案 0 :(得分:1)

是否有任何触发器可能导致与SELECT同时在审计表上的TRUNCATE无关紧要的事情(尽管事实上它是排行独家lock表示触发的内容类似于UPDATE?从PG 9.4 locking documentation开始,SELECTTRUNCATE确实会阻止彼此作为预期行为。相关的花絮是这些:

  

访问分享   仅与ACCESS EXCLUSIVE锁定模式冲突。   SELECT命令在引用的表上获取此模式的锁定。通常,任何只读取表但不修改表的查询都将获得此锁定模式。

     

ACCESS EXCLUSIVE   与所有模式的锁冲突(ACCESS SHARE,ROW SHARE,ROW EXCLUSIVE,SHARE UPDATE EXCLUSIVE,SHARE,SHOW ROW EXCLUSIVE,EXCLUSIVE和ACCESS EXCLUSIVE)。此模式保证持有者是以任何方式访问表的唯一事务。   由DROP TABLE,TRUNCATE,REINDEX,CLUSTER和VACUUM FULL命令获取。许多形式的ALTER TABLE也在此级别获得锁定。

更具体地讲述了该页面上的明确提示:

  

提示:只有ACCESS EXCLUSIVE锁才能阻止SELECT(不带FOR UPDATE / SHARE)语句。

至于在这种情况下该怎么做,如果你的用例容忍(可能是空闲的)连接的毫不间断的终​​止,那肯定是确保TRUNCATE成功的直接方式。

更灵活的替代方案可能是使用DELETE清除表格,然后跟进VACUUM之后的某些变体(DELETESELECT不会相互阻止,但会阻止UPDATE)。这种方法的适用性很大程度上取决于日常工作台的增长模式(如果它的最大尺寸不是每天不同,那么简单VACUUM可能是合适的)以及如何如果它是一张巨大的桌子,你需要在短期内回收这个空间 - 如果你需要快速和严重的空间,你可能需要在一个安静的窗口VACUUM FULL那个桌子,但VACUUM FULL不是温柔的锤子无论如何都要摆动。