在2015年的re:Invent谈话中,AWS提到,不仅应在更新或删除之后运行真空,而且还应在插入之后运行真空。这是演讲的相关部分:
http://www.youtube.com/watch?v=tZXp19q8RFo&t=16m2s
假设即使块仅接收插入,也必须对其进行一些清理,并且可以在第一次选择块时(降低读取速度)或在真空期间进行清理。这是真的吗?如果是,那么到底必须执行什么清理工作?
在2015年的re:Invent谈话中,AWS提到,不仅应在更新或删除之后运行真空,而且还应在插入之后运行真空。这是演讲的相关部分:
http://www.youtube.com/watch?v=tZXp19q8RFo&t=16m2s
假设即使块仅接收插入,也必须对其进行一些清理,并且可以在第一次选择块时(降低读取速度)或在真空期间进行清理。这是真的吗?如果是,那么到底必须执行什么清理工作?
Answers:
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
,对吗?