PostgreSQL 13: параллельный VACUUM

    На днях Амит Капила закоммитил патч Масахико Савады, который позволяет выполнять очистку в параллельном режиме. Сама таблица по-прежнему очищается одним (ведущим) процессом, но для очистки индексов он теперь может запускать фоновые рабочие процессы, по одному на каждый индекс. В ручном режиме это позволяет ускорить очистку больших таблиц с несколькими индексами; автоматическая очистка пока не использует эту возможность.

    Ссылки по теме:


    Как известно, процесс очистки таблицы состоит из нескольких фаз.

    Сначала таблица сканируется и в памяти собираются ссылки на ненужные («мертвые») версии строк. Память ограничена параметром maintenance_work_mem, поэтому за один раз все ссылки могут не поместиться.

    Затем последовательно (так было раньше) перебираются все индексы, и из них вычищаются указатели на найденные мертвые версии строк.

    Затем уже просмотренная часть таблицы сканируется еще раз и мертвые версии строк вычищаются уже из нее.

    Если за один раз не удалось обработать все мертвые версии строк, то память очищается и весь процесс повторяется снова с того места, на котором мы остановились в прошлый раз.

    Вся эта схема остается без изменений, но теперь индексы могут очищаться в параллель. Для этого ведущий процесс запускает несколько рабочих процессов, которые разбирают имеющиеся индексы и обрабатывают их. Один индекс обрабатывается только одним процессом. После того, когда все индексы очищены, рабочие процессы завершаются, а ведущий приступает к следующей фазе.

    Для примера возьмем таблицу перелетов ticket_flights демобазы. На ней один индекс, но можно создать еще пару.

    demo=# CREATE index on ticket_flights (fare_conditions);
    demo=# CREATE index on ticket_flights (amount);
    

    В параллельной обработке участвуют только те индексы, размер которых превышает значение параметра min_parallel_index_scan_size. Наши индексы подходят:

    demo=# SHOW min_parallel_index_scan_size;
    
     min_parallel_index_scan_size 
    ------------------------------
     512kB
    (1 row)
    
    demo=# SELECT pg_size_pretty(pg_relation_size(indexname::regclass))
    FROM pg_indexes
    WHERE tablename = 'ticket_flights';
    
     pg_size_pretty 
    ----------------
     325 MB
     187 MB
     180 MB
    (3 rows)
    

    Обновим половину строк, чтобы загрузить очистку работой:

    demo=# UPDATE ticket_flights SET amount = amount + 1 WHERE random() > 0.5;
    
    UPDATE 4194262
    

    Поехали.

    demo=# VACUUM VERBOSE ticket_flights;
    
    INFO:  vacuuming "bookings.ticket_flights"
    INFO:  launched 2 parallel vacuum workers for index vacuuming (planned: 2)
    INFO:  scanned index "ticket_flights_fare_conditions_idx" to remove 4194262 row versions by parallel vacuum worker
    DETAIL:  CPU: user: 1.84 s, system: 0.41 s, elapsed: 11.82 s
    INFO:  scanned index "ticket_flights_amount_idx" to remove 4194262 row versions by parallel vacuum worker
    DETAIL:  CPU: user: 2.31 s, system: 0.44 s, elapsed: 12.95 s
    INFO:  scanned index "ticket_flights_pkey" to remove 4194262 row versions
    ...
    INFO:  "ticket_flights": found 4194262 removable, 8391852 nonremovable row versions in 104885 out of 104885 pages
    DETAIL:  0 dead row versions cannot be removed yet, oldest xmin: 630
    There were 0 unused item identifiers.
    Skipped 0 pages due to buffer pins, 0 frozen pages.
    0 pages are entirely empty.
    CPU: user: 9.91 s, system: 4.40 s, elapsed: 121.40 s.
    VACUUM
    

    Тут видно, что ведущий процесс запустил два рабочих, а один индекс взял себе.

    Количество рабочих процессов можно указать явно (в любом случае оно, конечно, не будет превышать max_parallel_maintenance_workers, который не превышает max_worker_processes). Явым указанием можно, в частности, воспользоваться, чтобы отключить параллелизм:

    demo=# VACUUM (PARALLEL 0, VERBOSE) ticket_flights;
    

    Надеюсь, что эта тема получит дальнейшее развитие. Таблица могла бы сканироваться параллельно несколькими процессами (это было в исходном патче Савады, но не вошло в финальный), каждый индекс также мог бы очищаться параллельно. Обязательно нужно и автоматическую очистку научить пользоваться параллелизмом.

    P. S. Кстати, нам в нашу образовательную команду нужен человек. Чтобы умел и любил разбираться и объяснять. Где-то он есть, мы точно знаем, но пока прячется.
    Postgres Professional
    Разработчик СУБД Postgres Pro

    Похожие публикации

    Комментарии 5

      0
      А почему не дотащили в финал параллельную очистку таблицы и индекса? Печально как-то это, в патче было, Савада все сделал, но… увы…
        0

        Да там дискуссии вокруг этой темы уже не первый год идут. Вот, чтобы сдвинуть с мертвой точки, решили для начала закоммитить вразумительного объема кусок. Дальше уже будет легче его развивать.
        Это общая практика, со всеми крупными нововведениями так.

          0
          С параллелизмом очистки можно словить ошибки. Видимо до конца еще не изучена эта тема
          0
          Если индексы и таблица используют один диск (раздел), причём не находятся в кэше на момент начала очистки, параллельная обработка может оказаться в итоге гораздо медленней и добавить фрагментации.
            0

            Конечно. Диски должны успевать отдавать данные, чтобы загрузить много процессов, ядра свободные должны быть…
            Поэтому по уму надо протестировать параллельность на системе, максимально приближенной к боевой, и, если выгоды нет, закрутить параметры, чтобы она не использовалась.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое