Ускорить автоочистку в Postgres

У меня есть вопрос относительно настроек автоочистки / очистки Postgres. У меня есть таблица с 4,5 миллиардами строк, и был период времени с большим количеством обновлений, что привело к ~ 1,5 миллиардам мертвых кортежей. В этот момент автовакуумирование занимало много времени (дни). Глядя на представление pg_stat_progress_vacuum, я заметил, что:

max_dead_tuples = 178956970

что приводит к многократному повторному сканированию индекса (index_vacuum_count)
Согласно документам - max_dead_tuples – это количество мертвых кортежей, которые мы можем сохранить до того, как потребуется выполнить цикл очистки индекса, на основе Maintenance_work_mem.
Согласно это один мертвый кортеж требует 6 байтов пространства.
Таким образом, 6B x 178956970 = ~1GB
Но мои настройки

maintenance_work_mem = 20GB
autovacuum_work_mem = -1

Итак, что мне не хватает? почему не все мои 1,5-битные мертвые кортежи поместились в max_dead_tuples, поскольку 20 ГБ должно давать достаточно места, и почему было необходимо несколько прогонов?


person Rio    schedule 01.04.2021    source источник


Ответы (1)


Существует жестко запрограммированное ограничение в 1 ГБ на количество мертвых кортежей за один VACUUM цикл, см. источник:

/*
 * 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 увеличение лимита.

person Laurenz Albe    schedule 01.04.2021