在仅接收INSERT的表上运行VACUUM是否值得?


19

在2015年的re:Invent谈话中,AWS提到,不仅应在更新或删除之后运行真空,而且还应在插入之后运行真空。这是演讲的相关部分:

http://www.youtube.com/watch?v=tZXp19q8RFo&t=16m2s

假设即使块仅接收插入,也必须对其进行一些清理,并且可以在第一次选择块时(降低读取速度)或在真空期间进行清理。这是真的吗?如果是,那么到底必须执行什么清理工作?

Answers:


15

tl; dr:在提交数据后读取数据的第一个进程将设置提示位。这将弄脏页面,从而创建写活动。另一件事VACUUM(但不是其他命令)所做的是在适当的情况下将该页面标记为全可见。VACUUM最终将不得不击中桌子以冻结元组。

插入之后需要完成的工作并不是真正的清理工作,至少在其他工作VACUUM通常没有的意义上。在详细介绍之前,请注意,此答案基于当前(未发布)的9.6代码,并且尽管它可能影响可见性,但我忽略了流复制的影响。

由于MVCC,每次Postgres评估一个查询是否应该显示一个元组时,它都必须考虑创建该元组的事务(记录在xmin隐藏字段中)是否与其他条件一起提交。该检查非常昂贵,因此一旦知道所有当前打开的事务都可见一个事务,则在元组标头上设置“提示位”以表明这一点。该位的设置会使页面变脏,这意味着必须将其写入磁盘。如果下一个读取数据的命令SELECT突然产生大量写入流量,这可能会造成混乱。VACUUM在插入提交之后运行a 将避免这种情况。另一个重要的区别是VACUUM将始终提示页面上的元组(只要它在页面上获得了清除锁),但是大多数其他命令仅提示在命令开始之前是否执行了插入事务。

编写所有这些提示位的重要一点是VACUUM可以对其进行限制(默认情况下对autovacuum进行限制)。其他命令未受限制,将尽快生成脏数据。

VACUUM是将页面标记为全部可见的唯一方法,这是某些操作(尤其是仅索引扫描)对性能的重要考虑。如果您进行大插入,那么很可能有很多页面,除了新插入的元组之外什么都没有。VACUUM可以将这些页面标记为全可见,VACUUM前提是启动时最早运行的事务比插入数据的事务新

由于MVCC的工作原理,在大约20亿笔交易之前插入的元组必须标记为“ 冻结 ”。默认情况下,每2亿笔交易会自动进行一次vacuumum。批量插入后运行将vacuum_freeze_min_age设置为0的手动真空可以帮助减少这种影响。更积极地讲,VACUUM FREEZE插入后可以在表上运行。那将在下次冻结扫描发生时“重置时钟”。

如果您想了解特定的详细信息,请HEAPTUPLE_LIVE在致电HeapTupleSatisfiesVacuum()inside 之后查看案例lazy_scan_heap()。另请参阅HeapTupleSatisfiesVacuum()本身,并将其与进行比较HeapTupleSatisfiesMVCC()

我的另外两个演示可能很有趣。第一个视频可从http://www.pgcon.org/2015/schedule/events/829.en.html上获得,而第二个视频(我认为更好一点)可在https://www.youtube上获得。 com / watch?v = L8nErzxPJjQ


这非常有趣,并且还解释了某些EXPLAIN (ANALYZE, BUFFERS) outputs. But, if I understand things correctly, some of the hint bits (at least * COMMITTED`和*INVALID)中的脏页可以(可以)由COMMIT或设置ROLLBACK,对吗?
dezso

3
COMMIT和ROLLBACK实际上并不涉及数据页,因此不,这些命令特别不能提示。DML命令仍可以设置xmin和xmax提示状态,既可以为其他事务标记的元组,也可以为当前事务标记的元组设置。
Jim Nasby '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.