Concurrent VACUUM PostgreSQL
VACUUM выполняет следующие задачи:
- Удаление “мертвых” кортежей:
- Выполнение агрессивной “заморозки” кортежей;
- Другие задачи (обновление карт свободного пространства или FSM, а также карт видимости (VM): обновление статистики, например, pg_stat_all_tables и т.д.).
Предполагается, что читатели уже знакомы с такими терминами, как “мертвые” кортежи, FSM и CLOG; Если Вы еще не знакомы с данными понятиями, вернитесь к разделу 5. Информация о VM представлена в подразделе 6.2.
Следующий псевдокод описывает процесс VACUUM:
(1) FOR each table
(2) Acquire a ShareUpdateExclusiveLock lock for the target table
/* The first block */
(3) Scan all pages to get all dead tuples, and freeze old tuples if necessary
(4) Remove the index tuples that point to the respective dead tuples if exists
/* The second block */
(5) FOR each page of the table
(6) Remove the dead tuples, and Reallocate the live tuples in the page
(7) Update FSM and VM
END FOR
/* The third block */
(8) Clean up indexes
(9) Truncate the last page if possible
(10) Update both the statistics and system catalogs of the target table
Release the ShareUpdateExclusiveLock lock
END FOR
/* Post-processing */
(11) Update statistics and system catalogs
(12) Remove both unnecessary files and pages of the clog if possible
- (1) Получите каждую таблицу из указанных таблиц;
- (2) Осуществите блокировку ShareUpdateExclusiveLock для таблицы;
- (3) Просканируйте все страницы, чтобы получить все “мертвые” кортежи, при необходимости “заморозьте” старые кортежи;
- (4) Удалите индексs, указывающие на соответствующие “мертвые” кортежи, если они существуют;
- (5) Выполните шаги (6) и (7) для каждой страницы таблицы;
- (6) Удалите “мертвые” кортежи и перераспределите “живые” кортежи по странице;
- (7) Обновите FSM и VM целевой таблицы;
- (8) Очистите индексы с помощью функции index_vacuum_cleanup()@indexam.c;
- (9) Удалите последнюю страницу, если она не содержит ни одного кортежа;
- (10) Обновите статистику и системные каталоги, связанные с процессом VACUUM по отношению к целевой таблицы;
- (11) Обновите статистику и системных каталоги, связанные с процессом VACUUM;
- (12) По возможности удалите ненужные файлы и страницы CLOG.
Псевдокод состоит из двух частей: цикла для каждой таблицы и постобработки. Внутренний цикл можно разделить на три блока, каждый из которых выполняет определенные задачи.
Примечание: Параллельный VACUUM
В версии 13 была реализована совершено новая возможность, а именно выполнение очистки в параллельном режиме. Сама таблица по-прежнему очищается одним (ведущим) процессом, но для очистки индексов он теперь может запускать фоновые рабочие процессы, по одному на каждый индекс. В ручном режиме это позволяет ускорить очистку больших таблиц с несколькими индексами; автоматическая очистка пока не использует эту возможность.
Обратите внимание на то, что данную возможность можно реализовать только лишь в рамках операции VACUUM , AUTOVACUUM не поддерживает данную функцию.
Первый блок
Этот блок выполняет операцию заморозки и удаляет индексы, указывающие на “мертвые” кортежи.
Для того, чтобы составить список “мертвых” кортежей и по возможности заморозить старые кортежи PostgreSQL сканирует целевую таблицу. Полученный список хранится в локальной памяти под названием maintenance_work_mem. Описание процесса заморозки Вы найдете в подразделе 6.3.
После сканирования PostgreSQL удаляет индексные кортежи, обращаясь к списку “мертвых” кортежей. Этот процесс носит название "стадия очистки" или “cleanup stage”. Это достаточно дорогостоящий процесс, который был оптимизирован в 11 версии PostgreSQL.
В версиях 10 и более ранних версиях этап очистки выполняется всегда. В версиях 11 и новее, если индексом является B-дерево, выполнение (или невыполнение) данной стадии определяется конфигурационным параметром под названием vacuum_cleanup_index_scale_factor.
Подробное описание данного параметра доступно по ссылке.
Если параметр память maintenance_work_mem заполнен, а сканирование не завершено, PostgreSQL переходит к шагам (4) - (7) и затем возвращается к шагу (3), после чего продолжает сканирование.
Второй блок
Этот блок удаляет “мертвые” кортежи и обновляет FSM и VM для каждой таблицы:
Предположим, что таблица содержит три страницы. Сосредоточимся на 0-й странице (т. е. первой). Эта страница содержит три кортежа. Tuple_2 является “мертвым” кортежем (рис. 69 (1)). В этом случае PostgreSQL удаляет Tuple 2 и переупорядочивает оставшиеся кортежи для того, чтобы устранить фрагментацию. Затем он обновляет FSM и VM этой страницы (рис. 69(2)). PostgreSQL продолжает этот процесс до перехода к последней странице.
Обратите внимание на то, что ненужные указатели строк не удаляются. Они будут повторно использованы в будущем. Это связано с тем, что при удалении линейных указателей все кортежи связанных с ними индексов должны быть обновлены.
Третий блок
Третий блок выполняет очистку, а также обновляет статистику и системные каталоги, связанные с вакуумной обработкой, для каждой целевой таблицы.
Кроме того, если последняя страница не содержит кортежей, она удаляется из файла таблицы.
Постобработка
Когда вакуумная обработка завершена, PostgreSQL обновляет всю статистику и системные каталоги, связанные с вакуумной обработкой. Кроме того, по возможности удаляются ненужные части CLOG (Раздел 6.4).
Примечание: Ring Buffer
Вакуумная обработка использует структуру ring buffer, описанную в разделе 8.5. Поэтому обработанные страницы не кэшируются в общих буферах.




