加快 Postgres 中的 autovacuum
Speed up autovacuum in Postgres
我有一个关于 Postgres autovacuum / vacuum 设置的问题。
我有一个包含 45 亿行的 table,并且有一段时间有大量更新导致大约 15 亿个死元组。此时 autovacuum 需要很长时间(几天)才能完成。
在查看 pg_stat_progress_vacuum 视图时,我注意到:
max_dead_tuples = 178956970
导致多次索引重新扫描(index_vacuum_count)
根据 docs - max_dead_tuples 是我们可以在需要执行索引真空循环之前存储的一些死元组,基于 maintenance_work_mem.
根据 this 一个死元组需要 6 个字节的 space.
所以 6B x 178956970 = ~1GB
但是我的设置是
maintenance_work_mem = 20GB
autovacuum_work_mem = -1
那我错过了什么?为什么我的 1.5b 死元组不适合 max_dead_tuples,因为 20GB 应该足够 space,为什么需要多次运行?
一个 VACUUM
周期中的死元组数量有 1GB 的硬编码限制,请参阅 the source:
/*
* Return the maximum number of dead tuples we can record.
*/
static long
compute_max_dead_tuples(BlockNumber relblocks, bool useindex)
{
long maxtuples;
int vac_work_mem = IsAutoVacuumWorkerProcess() &&
autovacuum_work_mem != -1 ?
autovacuum_work_mem : maintenance_work_mem;
if (useindex)
{
maxtuples = MAXDEADTUPLES(vac_work_mem * 1024L);
maxtuples = Min(maxtuples, INT_MAX);
maxtuples = Min(maxtuples, MAXDEADTUPLES(MaxAllocSize));
/* curious coding here to ensure the multiplication can't overflow */
if ((BlockNumber) (maxtuples / LAZY_ALLOC_TUPLES) > relblocks)
maxtuples = relblocks * LAZY_ALLOC_TUPLES;
/* stay sane if small maintenance_work_mem */
maxtuples = Max(maxtuples, MaxHeapTuplesPerPage);
}
else
maxtuples = MaxHeapTuplesPerPage;
return maxtuples;
}
MaxAllocSize
在 src/include/utils/memutils.h
中定义为
#define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
您可以游说 pgsql-hackers 列表以增加限制。
我有一个关于 Postgres autovacuum / vacuum 设置的问题。 我有一个包含 45 亿行的 table,并且有一段时间有大量更新导致大约 15 亿个死元组。此时 autovacuum 需要很长时间(几天)才能完成。 在查看 pg_stat_progress_vacuum 视图时,我注意到:
max_dead_tuples = 178956970
导致多次索引重新扫描(index_vacuum_count)
根据 docs - max_dead_tuples 是我们可以在需要执行索引真空循环之前存储的一些死元组,基于 maintenance_work_mem.
根据 this 一个死元组需要 6 个字节的 space.
所以 6B x 178956970 = ~1GB
但是我的设置是
maintenance_work_mem = 20GB
autovacuum_work_mem = -1
那我错过了什么?为什么我的 1.5b 死元组不适合 max_dead_tuples,因为 20GB 应该足够 space,为什么需要多次运行?
一个 VACUUM
周期中的死元组数量有 1GB 的硬编码限制,请参阅 the source:
/*
* Return the maximum number of dead tuples we can record.
*/
static long
compute_max_dead_tuples(BlockNumber relblocks, bool useindex)
{
long maxtuples;
int vac_work_mem = IsAutoVacuumWorkerProcess() &&
autovacuum_work_mem != -1 ?
autovacuum_work_mem : maintenance_work_mem;
if (useindex)
{
maxtuples = MAXDEADTUPLES(vac_work_mem * 1024L);
maxtuples = Min(maxtuples, INT_MAX);
maxtuples = Min(maxtuples, MAXDEADTUPLES(MaxAllocSize));
/* curious coding here to ensure the multiplication can't overflow */
if ((BlockNumber) (maxtuples / LAZY_ALLOC_TUPLES) > relblocks)
maxtuples = relblocks * LAZY_ALLOC_TUPLES;
/* stay sane if small maintenance_work_mem */
maxtuples = Max(maxtuples, MaxHeapTuplesPerPage);
}
else
maxtuples = MaxHeapTuplesPerPage;
return maxtuples;
}
MaxAllocSize
在 src/include/utils/memutils.h
中定义为
#define MaxAllocSize ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
您可以游说 pgsql-hackers 列表以增加限制。