为什么 PostgreSQL 的 TRUNCATE 不具备 MVCC 安全性?
数据小陈
结论
TRUNCATE 不具备 MVCC 安全性,因为它清空表时不像 DELETE 那样为每一行保留旧版本供旧快照读取。事务如果在截断前取得快照,却在截断提交后才读取这张表,可能会看到空表。
TRUNCATE 和 DELETE 的区别
PostgreSQL 主要通过行版本控制 MVCC 可见性。执行 DELETE 时,数据库会产生行级变更。仍符合可见性条件的旧快照可以读取旧行版本,直到相关版本可以被清理。
TRUNCATE 会清空整张表,不会逐行删除,也不会为旧快照保留可见的行版本。因此,即使事务使用的是旧快照,截断提交后也可能看不到截断前的行。这就是文档所说的“不具备 MVCC 安全性”。
并发事务可能看到什么
例如,事务 A 先取得快照,但暂时没有读取 items 表。随后,事务 B 截断并提交该表。事务 A 之后读取 items 时,可能看到空表,即使它使用的快照早于事务 B 的截断操作。
TRUNCATE 会对表加上强锁,阻止其他事务在锁持有期间并发访问该表。但锁不会让旧快照在截断提交后重新看到此前的行,因此事务之后读取时仍可能看到空表。
需要旧快照继续读取旧行时
如果业务要求截断前已取得的快照仍能读到原有行,可以考虑使用 DELETE:
DELETE FROM items;
DELETE 会逐行处理,通常比 TRUNCATE 成本更高。具体性能和清理时机取决于表大小、事务情况等因素。使用 TRUNCATE 时,应确认业务能够接受截断提交后,旧快照事务可能读到空表。
备注:内容仅供参考。
