PostgreSQL参数解析autovacuum_work_mem

PostgreSQL 提供了参数 autovacuum_work_mem 用来控制每个 autovacuum 工作进程可以使用的最大内存数量。如果指定该参数时没有带单位,那么其默认单位是 KB。该参数默认值为 -1,其大小等同于 maintenance_work_mem 参数值。该参数可以在 postgresql.conf 文件中或者数据库启动的命令行中设置。

对于收集死元组的集合,autovacuum 最多只能使用 1GB 的内存,因此将 autovacuum_work_mem 设置为高于 1GB的值时,对 autovacuum 在扫描表收集的死元组数量是没有影响的。

  • 默认值,-1,表示使用 maintenance_work_mem 参数的值作为本参数的值
  • 最小值 1024,即 1MB,如果设置的小于 1024,自动转成 1024
  • 最大值为 (INT_MAX / 1024)

在内核实现上,对于 autovacuum_work_mem 参数的使用场所有 2 处:

  1. 计算表最大死元组数量,在 compute_max_dead_tuples() 函数中通过 autovacuum_work_mem 参数计算使用索引场景下的表死元组的最大数量,最大数量不会超过 1GB。
  2. 在ginInsertCleanup() 函数中,forceCleanup 为 true 的情况下,workMemory 就是 autovacuum_work_mem 的值。当满足 accum.allocatedMemory >= workMemory * 1024L 时就会考虑将内存中的数据刷盘处理。

相关代码:

如果 autovacuum_work_mem 为 -1,则使用 maintenance_work_mem 参数的值:

autovacuum_work_mem != -1 ?
    autovacuum_work_mem : maintenance_work_mem;

计算表的最大死元组数量:

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;
}

ginInsertCleanup() 函数 forceCleanup 模式下超过最大内存限制时内存数据刷盘。

void
ginInsertCleanup(GinState *ginstate, bool full_clean,
                 bool fill_fsm, bool forceCleanup,
                 IndexBulkDeleteResult *stats)
{
    if (forceCleanup)
    {
        workMemory =
            (IsAutoVacuumWorkerProcess() && autovacuum_work_mem != -1) ?
            autovacuum_work_mem : maintenance_work_mem;
    }
    
        if (GinPageGetOpaque(page)->rightlink == InvalidBlockNumber ||
            (GinPageHasFullRow(page) &&
             (accum.allocatedMemory >= workMemory * 1024L)))
        {
            ... /* 内存刷盘 */
        }
}

文章评论

0条评论