Postgres 9.4,Ubuntu 10
我一直无法在这里找到这个确切的问题,所以在这里:
对于我数据库中的每个表t,我有一个表t_audit。表t上的每次删除,插入和更新都会触发一个将记录插入表t_audit的函数。
每晚,一个进程会截断每个t_audit表。
昨晚,表t上的select会阻止t_audit上的截断继续进行。我当时没有保存pg_stat_activity中的内容,但我确实保存了blocking_locks()的输出。
我不确定为什么t上的select会阻塞t_audit上的截断。因为我没有保存pg_stat_activity,所以我可以假设最好的选择是“在事务中空闲”。我问当时正在运行查询的人,他说他没有在事务中运行更新。他确实在选择之前更新了表格t。他没有关闭他的连接,因为pid仍然有效,直到我在pid上运行了pg_terminate_backend。
之前有没有人遇到过这个问题?除了在调用truncate之前在“事务中空闲”的任何pid上运行pg_terminate_backend之外,是否有推荐的过程?
感谢您阅读并花时间回复。
答案 0 :(得分:1)
是否有任何触发器可能导致与SELECT
同时在审计表上的TRUNCATE
无关紧要的事情(尽管事实上它是排行独家lock表示触发的内容类似于UPDATE
?从PG 9.4 locking documentation开始,SELECT
和TRUNCATE
确实会阻止彼此作为预期行为。相关的花絮是这些:
访问分享 仅与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
之后的某些变体(DELETE
和SELECT
不会相互阻止,但会阻止UPDATE
)。这种方法的适用性很大程度上取决于日常工作台的增长模式(如果它的最大尺寸不是每天不同,那么简单VACUUM
可能是合适的)以及如何如果它是一张巨大的桌子,你需要在短期内回收这个空间 - 如果你需要快速和严重的空间,你可能需要在一个安静的窗口VACUUM FULL
那个桌子,但VACUUM FULL
不是温柔的锤子无论如何都要摆动。