在监视我的数据库上的 autovacuum 活动时,我注意到带有标记的 autovacuum(to prevent wraparound)
似乎比“常规”autovacuum 花费的时间更长。这让我开始尝试了解各种“种类”或 autovacuum 的性能/行为差异。
从文档VACUUM
中,我确定了 autovacuum 可能是一个表的几个不同原因:
表中有需要冻结的旧事务 (
relfrozenxid > min(autovacuum_freeze_max_age, table.autovacuum_freeze_max_age
)。这是“(to prevent wraparound)
”自动清理。自上次
VACUUM
超过“真空阈值”以来表中废弃的元组数
还有其他我想念的吗?
似乎为手册暴露的“攻击性”旋钮VACUUM
是FREEZE
和DISABLE_PAGE_SKIPPING
。这些不同类型的 autovacuum 是否使用过这些选项,如果使用过,什么时候使用过?
这是可以预料的。他们必须做更多的工作。这些本质上是
vacuum freeze
由 autovacuum 运行的。FrozenTransactionId
冻结元组意味着通过用特殊的固定值(xid 3)替换它们的事务 ID,将它们标记为对所有当前和未来事务可见。由于元组的 xmin 存储在磁盘上的元组中,这意味着每个尚未冻结并且是冻结候选者的元组都需要修改。这通常会触发整页写入,因为元组通常是自上次检查点以来页面上的第一次修改,导致每个页面上的第一个冻结元组写入 8k。(这也会使 WAL 和 PITR 备份、复制流等膨胀)。PostgreSQL 9.6 及以下版本中的冻结 vacuum 不能跳过表的部分;他们每次都必须扫描整张桌子,即使只有一小部分是冻结的候选者。
除非你调整 autovacuum 以更积极地冻结,否则它往往会很晚地离开强制冻结,然后立即做很多工作。这是高效的,因为我们不会多次扫描表,但代价高昂,因为我们每次处理它时都会做很多工作。
当 vacuum 不冻结元组时,它仍在做很多相同的工作。但它通常在每次传递时触及的页面数量要少得多,因为它只需要关心那些由 since
xmax
-committed 事务设置了 not-for-locking-only 的元组。具有这些元组的页面也更有可能在缓存中,因为它们最近被删除了,并且它们的任何 multixact 数据也更有可能在缓存中。您可以通过以下方式更快地冷冻真空吸尘器:
降低
autovacuum_vacuum_cost_delay
- 这将使 autovacuum 使用更多资源并给系统带来更多负载,但运行速度更快。降低
autovacuum_freeze_max_age
,让他们跑得更频繁,每次做的工作更少。这总体上效率较低,因为每次都必须扫描整个表,在我们读取表时从操作系统缓冲区缓存中逐出页面。(Pg 使用环形缓冲区进行序列扫描,但操作系统通常不会)。但这意味着我们每次通过的写入次数更少,每次通过所花费的时间也更少。COPY
使用选项在 d it或d itFREEZE
的同一事务中批量加载表。以这种方式加载的元组开始预冻结。(有关详细信息,请参阅上的手册)。TRUNCATE
CREATE
COPY
在批量加载表格后手动冻结表格,因此您可以在您控制的时间支付冻结成本。
就个人而言,我希望 normal
VACUUM
s(和 autovacuums)做更多的机会冻结;特别是,如果我们刚刚触摸了页面上的项目指针数组以将一些元组标记为可用空间,我们可能应该在页面脏时扫描可冻结的元组。这将与 PostgreSQL 10 中新的冻结映射代码一起很好地发挥作用。PostgreSQL 9.6 中的冻结有一些重大改进,减少了重复清理表的影响并使冻结成本更低。由于在可见性地图中引入了冻结地图功能,我们可以避免扫描整个表格,跳过冻结页面。请参阅提交 a892234 和 fd31cd265。
我认为 PostgreSQL 10 也正在进行工作,以完全避免修改磁盘上的元组以将其标记为冻结的需要,但找不到相关的邮件列表线程 atm。