在 2015 年的 re:Invent 演讲中,AWS 提到,vacuum 不仅应该在更新或删除之后运行,还应该在插入之后运行。以下是谈话的相关部分:
http://www.youtube.com/watch?v=tZXp19q8RFo&t=16m2s
假设必须对块进行一些清理,即使它们只接收到插入,并且可以在第一次选择块时(减慢读取速度)或在真空期间进行清理。这是真的吗?如果是这样,究竟必须进行哪些清理工作?
在 2015 年的 re:Invent 演讲中,AWS 提到,vacuum 不仅应该在更新或删除之后运行,还应该在插入之后运行。以下是谈话的相关部分:
http://www.youtube.com/watch?v=tZXp19q8RFo&t=16m2s
假设必须对块进行一些清理,即使它们只接收到插入,并且可以在第一次选择块时(减慢读取速度)或在真空期间进行清理。这是真的吗?如果是这样,究竟必须进行哪些清理工作?
tl;dr:提交后读取数据的第一个进程将设置提示位。这将弄脏页面,创建写入活动。另一件事
VACUUM
(但不是其他命令)所做的是将页面标记为全部可见,如果合适的话。VACUUM
最终将不得不敲桌子来冻结元组。插入后需要完成的工作并不是真正的清理,至少不是其他工作
VACUUM
通常所做的那样。在详细介绍之前,请注意,此答案基于当前(未发布的)9.6 代码,我忽略了流复制的影响,即使它可能会影响可见性。由于MVCC,每次 Postgres 评估元组是否应该对查询可见时,它必须考虑创建元组的事务(记录在 xmin 隐藏字段中)是否已提交,以及其他一些标准。该检查很昂贵,因此一旦知道所有当前打开的事务都可以看到事务,就会在元组标头上设置一个“提示位”来指示这一点。该位的设置会弄脏页面,这意味着必须将其写入磁盘。如果下一个读取数据的命令
SELECT
突然产生大量写入流量,这可能会非常令人困惑。VACUUM
在插入提交之后运行 a将避免这种情况。另一个重要的区别是VACUUM
总是会提示页面上的元组(只要它在页面上获得了清理锁),但大多数其他命令只会提示插入事务是否在命令开始之前提交。关于编写所有这些提示位的重要一点是
VACUUM
可以限制(默认情况下自动清空是限制的)。其他命令不会受到限制,并且会尽快生成脏数据。VACUUM
是将页面标记为全部可见的唯一方法,这是某些操作(特别是仅索引扫描)的重要性能考虑因素。如果您进行大型插入,很可能有许多页面只有新插入的元组。VACUUM
可以潜在地将这些页面标记为全部可见,但前提VACUUM
是启动时最旧的正在运行的事务比插入数据的事务新。由于 MVCC 的工作方式,插入超过约 20 亿次交易的元组必须标记为“冻结”。默认情况下,autovacuum 将在每 2 亿笔交易中执行此操作。在批量插入后运行手动真空吸尘器并将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