Download - PostgreSQL Vacuum: Nine Circles of Hell
![Page 1: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/1.jpg)
Девять кругов ада или PostgreSQL Vacuum
Лесовский Алексей, 2016.11PostgreSQL-Consulting
![Page 2: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/2.jpg)
Как быстро сломать Postgres
Часто и много обновлять таблицу.
Отключить вакуум.
Практический тест и как воспроизвести: https://goo.gl/Tql87l
● До: 3565.5 tps, 0.839 ms.
● После: 172.8 tps, 17.373 ms.
![Page 3: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/3.jpg)
Что важно помнить
Вакуум – это важно, его нельзя игнорировать.
Если вакуум не настроен, производительность деградирует.
Вакуум не страшен, настраивать его не сложно.
![Page 4: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/4.jpg)
Вакуум, и как это работает
MVCC, Postmaster, Autovacuum Launcher & Workers.
Что там внутри Worker'а.
Подготовка к вакууму, costs, wraparound.
Вакуум индексов, таблиц и их страниц.
Слайды: https://goo.gl/iScq7g
![Page 5: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/5.jpg)
MVCC
MVCC – Multiversion Concurrency Control:
● предлагает хорошую конкурентность;
● в условиях значительной read/write-активности;
● читатели не блокируют писателей и наоборот.
![Page 6: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/6.jpg)
MVCC
MVCC – Multiversion Concurrency Control:
● предлагает хорошую конкурентность;
● в условиях значительной read/write активности;
● читатели не блокируют писателей и наоборот.
● Почти ;)
![Page 7: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/7.jpg)
MVCC
![Page 8: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/8.jpg)
MVCC
![Page 9: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/9.jpg)
MVCC
![Page 10: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/10.jpg)
MVCC
![Page 11: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/11.jpg)
MVCC
![Page 12: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/12.jpg)
MVCC
![Page 13: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/13.jpg)
Postmaster
Postmaster работает в бесконечном цикле.
● запуск фоновых процесов (checkpointer, bgwriter, walwriter, ...);
● и в т.ч. autovacuum launcher;
● вообще там много всего…
AV Launcher будет перезапущен, если что-то пойдет не так.
![Page 14: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/14.jpg)
Autovacuum Launcher
Инициализация.
Запуск воркера в случае emergency.
Создание списка БД.
Запуск бесконечного цикла (SIGTERM ?):
![Page 15: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/15.jpg)
Autovacuum Launcher
Инициализация.
Запуск воркера в случае emergency.
Создание списка БД.
Запуск бесконечного цикла (SIGTERM ?):
● обработка SIGTERM, SIGHUP, SIGUSR2;
● запуск воркера для баз в списке (autovacuum_naptime).
![Page 16: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/16.jpg)
Как выбирается база для обработки?
Определяем xidForceLimit = recentXid – autovacuum_freeze_max_age.
Риск wraparound с самым старым datfrozenxid/datminmxid.
Базы, которые давно не посещал вакуум.
Пропускаем базы, обработанные недавно.
![Page 17: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/17.jpg)
Когда кандидат выбран
Отметка в shared памяти (имя БД, время запуска).
Отправка сигнала Postmaster“у (флажок + SIGUSR1).
Postmaster принимает сигнал и делает fork (connection limit?).
Воркер запущен.
![Page 18: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/18.jpg)
Postmaster & Co
![Page 19: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/19.jpg)
Worker
Инициализация (signals, file descriptors, filemgr, bufmgr, smgr, shm, local struct).
Установка параметров:
● zero_damaged_pages=false
● statement_timeout=0, lock_timeout=0
● default_transaction_isolation="read commited"
● synchronous_commit=local
![Page 20: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/20.jpg)
Worker
Получение имени БД из av_startingWorker.
Регистрация в runningWorkers и сброс av_startingWorker.
Отправка SIGUSR2 процессу AV Launcher.
Инициализация в качестве postgres backend.
![Page 21: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/21.jpg)
pg_class
Составляем список таблиц для обработки
● таблицы и мат. представления;
● TOAST таблицы.
![Page 22: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/22.jpg)
pg_class
Выбираются только таблицы и мат. представления (pg_class.relkind):
● чтение статистики и параметров таблиц (pg_class.reloptions);
● запуск relation_needs_vacanalyze() – vaccum, analyze или wraparound?
● таблица является временной (pg_class.relpersistence)?
Для TOAST запоминаем ассоциацию с родительской таблицей.
![Page 23: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/23.jpg)
Wraparound
![Page 24: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/24.jpg)
Wraparound
recentXid – текущая транзакция.
vacuum_freeze_min_age – строки с возрастом старше должны быть заморожены.
vacuum_freeze_table_age – полное сканирование, если достигнут возраст.
autovacuum_freeze_max_age – возраст принудительного запуска wraparound-вакуума.
![Page 25: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/25.jpg)
А нужен ли вакуум?
Проверка необходимости вакуума или сбора статистики (или все вместе).
Определение пороговых параметров:
● параметры reloptions (от основной или TOAST-таблицы);
● параметры конфигурации (postgresql.conf);
● для freeze_max_age выбираем минимум (reloptions vs. postgresql.conf);
![Page 26: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/26.jpg)
А нужен ли вакуум?
Принудительный вакуум, если есть риск wraparound:
● xidForceLimit = recentXid – freeze_max_age;
● multiForceLimit = recentMulti – multixact_freeze_max_age;
● вакуум обязателен, если pgclass.relfrozenxid или relminmxid старше порогов;
● если нет риска wraparound и AV отключен – пропускаем таблицу.
![Page 27: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/27.jpg)
А нужен ли вакуум?
pg_stat_all_tables.n_dead_tup, pg_stat_all_tables.n_mod_since_analyze
reltuples = classForm->reltuples;
vactuples = tabentry->n_dead_tuples;
anltuples = tabentry->changes_since_analyze;
vacthresh = (float4) vac_base_thresh + vac_scale_factor * reltuples;
anlthresh = (float4) anl_base_thresh + anl_scale_factor * reltuples;
*dovacuum = force_vacuum || (vactuples > vacthresh);
*doanalyze = (anltuples > anlthresh);
![Page 28: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/28.jpg)
А нужен ли вакуум?
autovacuum_vacuum_threshold = 50 # min number of row updates # before vacuum
autovacuum_analyze_threshold = 50 # min number of row updates# before analyze
autovacuum_vacuum_scale_factor = 0.2 # fraction of table size # before vacuum
autovacuum_analyze_scale_factor = 0.1 # fraction of table size# before analyze
![Page 29: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/29.jpg)
Подготовка к вакууму
Все таблицы проверены – список составлен – закрываем pg_class.
Выбор стратегии работы с shared памятью:
● BAS_BULKREAD: ring_size = 256 * 1024 / BLCKSZ;
● BAS_BULKWRITE: ring_size = 16 * 1024 * 1024 / BLCKSZ;
● BAS_VACUUM: ring_size = 256 * 1024 / BLCKSZ; (32kB).
Выбор первой таблицы из списка.
![Page 30: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/30.jpg)
Расчет cost параметров
vacuum_cost_delay = 0 # 0-100 millisecondsvacuum_cost_page_hit = 1 # 0-10000 creditsvacuum_cost_page_miss = 10 # 0-10000 creditsvacuum_cost_page_dirty = 20 # 0-10000 creditsvacuum_cost_limit = 200 # 1-10000 creditsautovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for
# autovacuum, in milliseconds;# -1 means use vacuum_cost_delay
autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for# autovacuum, -1 means use# vacuum_cost_limit
![Page 31: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/31.jpg)
Расчет cost параметров
Разделение I/O поровну между всеми воркерами.
Объем I/O определяется с помощью cost_limit, cost_delay.
● autovacuum_vacuum_cost_limit или vacuum_cost_limit;
● autovacuum_vacuum_cost_delay или vacuum_cost_delay;
Ничего не делать, если параметры не установлены (<= 0).
![Page 32: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/32.jpg)
Вакуум, вакуум
![Page 33: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/33.jpg)
Вакуум, вакуум
autovacuum_do_vac_analyze() – автовакуум и/или autoanalyze.
ExecVacuum() – точка входа ручных VACUUM и ANALYZE команд.
vacuum() – точка входа для вакуума и сбора статистики.
![Page 34: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/34.jpg)
VACUUM или ANALYZE
Cost-based вакуум в случае VacuumCostDelay > 0.
Обработка таблицы в зависимости от потребности:
● vacuum_rel() и analyze_rel();
Завершение обработки:
● обновление pg_database.datfrozenxid и чистка pg_clog;
● завершение работы.
![Page 35: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/35.jpg)
Блокировки
Проверка отмены со стороны пользователя.
Выбор блокировки: ExclusiveLock или ShareUpdateExclusiveLock
Открываем таблицу и берем блокировку.
Не удалось взять блокировку?
● autovacuum: пишем в лог "skipping vacuum of %s --- lock not available";
● не удалось открыть (таблица удалена?), завершаем работу.
![Page 36: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/36.jpg)
Проверка таблицы
Проверка привилегий (superuser, владелец таблицы, владелец БД).
Проверка, что объект, вообще vacuumable (таблицы, мат.вью, TOAST).
Пропуск временных таблиц других бэкендов.
Запоминаем ассоциацию с TOAST (исключение – автовакуум).
Переключение userid на владельца таблицы.
![Page 37: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/37.jpg)
Do the actual work
/* * Do the actual work --- either FULL or "lazy" vacuum */
VACUUM FULL?
● закрываем таблицу, но продолжаем держать блокировку;
● cluster_rel() – VACUUM FULL является вариантом CLUSTER; см. cluster.c.
В любом другом случае – lazy_vacuum_rel().
![Page 38: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/38.jpg)
Таблица обработана
Вакуум завершен – таблица обработана.
Закрытие таблицы.
При наличии TOAST, переходим к ней (также vacuum_rel()).
![Page 39: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/39.jpg)
lazy_vacuum_rel()
Установка пороговых значений для заморозки:
● freeze_min_age, freeze_table_age;
● multixact_freeze_min_age, multixact_freeze_table_age;
![Page 40: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/40.jpg)
lazy_vacuum_rel()
Установка пороговых значений для заморозки:
● freeze_min_age, freeze_table_age;
● multixact_freeze_min_age, multixact_freeze_table_age;
● oldestXmin – оценка, когда строка считается DEAD или RECENTLY_DEAD;
● freezeLimit – старше этого порога все строки замораживаются;
● xidFullScanLimit – полное сканирование таблицы, если relfrozenxid старше порога;
![Page 41: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/41.jpg)
lazy_vacuum_rel()
Установка пороговых значений для заморозки:
● freeze_min_age, freeze_table_age;
● multixact_freeze_min_age, multixact_freeze_table_age;
● oldestXmin – оценка, когда строка считается DEAD или RECENTLY_DEAD;
● freezeLimit – старше этого порога все строки замораживаются;
● xidFullScanLimit – полное сканирование таблицы, если relfrozenxid старше порога;
● multiXactCutoff – порог для удаления всех MultiXactIds из Xmax;
● mxactFullScanLimit – полное сканирование, если relminmxid старше порога.
![Page 42: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/42.jpg)
lazy_vacuum_rel()
Установка пороговых значений для заморозки:
● freeze_min_age, freeze_table_age;
● multixact_freeze_min_age, multixact_freeze_table_age;
● oldestXmin – оценка, когда строка считается DEAD или RECENTLY_DEAD;
● freezeLimit – старше этого порога все строки замораживаются;
● xidFullScanLimit – полное сканирование таблицы, если relfrozenxid старше порога;
● multiXactCutoff – порог для удаления всех MultiXactIds из Xmax;
● mxactFullScanLimit – полное сканирование, если relminmxid старше порога.
Сравниваем relfrozenxid/relminmxid с пороговыми значениями.
![Page 43: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/43.jpg)
lazy_vacuum_rel()
Открываем индексы → вакуум с lazy_scan_heap() → Закрываем индексы.
Считаем, вся ли таблица была просканирована:
scanned_pages + frozenskipped_pages = rel_pages
Если возможно, обрезаем таблицу.
Обновляем Free Space Map, pg_class:
● relpages, reltuples, relallvisible, relhasindex, refrozenxid/relminmxid (full scan only).
Сохраняем статистику в stats коллектор (n_live_tupe, n_dead_tuples).
Пишем сообщение в журнал при log_min_duration >= 0.
Конец.
![Page 44: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/44.jpg)
Таблица обработана (напоминание)
Вакуум завершен – таблица обработана.
Закрытие таблицы.
При наличии TOAST, переходим к ней (также vacuum_rel()).
![Page 45: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/45.jpg)
/* lazy_scan_heap() – scan an open heap relation */
Выделяем память для хранения dead строк (autovacuum_work_mem);
Проверяем страницы, которые можно пропустить:
● ALL_FROZEN и ALL_VISIBLE флаги (в соотв. с visibility map);
● в случае full scan нельзя пропускать ALL_VISIBLE страницы;
● всегда пропускаем ALL_FROZEN страницы;
● всегда сканируем последний блок – вдруг таблицу можно обрезать.
После каждого блока выполняем vacuum_delay_point().
![Page 46: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/46.jpg)
lazy_scan_heap()
Начинаем цикл проверки с первого непропускаемого блока:
● и снова ищем следующий блок, который нельзя пропускать;
● проверяем хранилище dead строк на предмет переполнения;
● читаем содержимое страницы, считаем costs;
● пытаемся взять блокировку для чистки блока (для HOT).
Блок будет пропущен, если блокировка провалится (искл. full-scan).
![Page 47: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/47.jpg)
lazy_scan_heap()
Проверка страницы на наличие строк — кандидатов в заморозку:
● всегда чистим неинициализированные страницы;
● пропускаем пустые страницы;
● проверяем нормальные страницы;
● dead и redirect никогда не нужно морозить;
● проверяем, что любое из XID-полей (xmin,xmax,xvac) старше порога.
![Page 48: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/48.jpg)
lazy_scan_heap()
Продолжаем основной цикл проверки страниц…
Новые страницы инициализируем
● помечаем как грязные, отмечаем в Free Space Map.
Пустые страницы:
● ставим отметку ALL_VISIBLE и ALL_FROZEN;
● помечаем как грязные, делаем запись в WAL, обновляем VM и FSM.
![Page 49: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/49.jpg)
Heap Only Tuples
![Page 50: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/50.jpg)
Heap Only Tuples
![Page 51: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/51.jpg)
Heap Only Tuples
![Page 52: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/52.jpg)
Heap Only Tuples
![Page 53: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/53.jpg)
Heap Only Tuples
![Page 54: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/54.jpg)
Heap Only Tuples
Чистка всех HOT-цепочек в странице:
● проверяем указатели на предмет HOT-цепочек.
● перестраиваем HOT-цепочки (но не вносим никаких изменений в страницу):
● чистим dead и битые HOT-цепочки;
● перестраиваем редиректы.
![Page 55: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/55.jpg)
Heap Only Tuples
Применяем изменения в критической секции:
● обновляем указатели;
● делаем дефрагментацию.
Убираем отметку "page is full", помечаем страницу как грязную, пишем WAL.
Завершаем критическую секцию.
(Если доступных для чистки цепочек нет, то ничего не делаем)
![Page 56: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/56.jpg)
lazy_scan_heap()Проверка страницы, сбор vacuumable строк, проверка на возможность заморозки.
Проверка указателей:
● пропускаем unused, dead, redirects; проверяем только нормальные.
HeapTupleSatisfiesVacuum():
● HEAPTUPLE_DEAD: vacuumable (пропускаем, если это HOT-цепочка).
● HEAPTUPLE_LIVE: хорошая строка, вакуум не нужен.
● HEAPTUPLE_RECENTLY_DEAD: нельзя удалять строку.
● HEAPTUPLE_INSERT_IN_PROGRESS и HEAPTUPLE_DELETE_IN_PROGRESS: пропускаем, страница не является ALL_VISIBLE.
Запоминаем vacuumable строки в хранилище dead-строк.
![Page 57: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/57.jpg)
lazy_scan_heap()
Проверяем неудаляемые строки на возможность заморозки.
● подготавливаем строку, если можно морозить (составляем локальный infomask).
Если есть строки для заморозки:
● открываем критическую секцию;
● отмечаем страницу как грязную;
● устанавливаем биты в infomask-строки;
● пишем изменения в WAL;
● завершаем критическую секцию.
![Page 58: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/58.jpg)
lazy_scan_heap()
Если нет индексов, сразу вакуумим страницу.
Обновляем Visibility Map и Free Space Map.
Переходим к следующему блоку
или завершаем цикл, если все блоки просканированы.
![Page 59: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/59.jpg)
lazy_scan_heap()
Сохраняем статистику, считаем новое pg_class.reltuples.
Если еще есть строки к удалению, выполняем завершающий цикл вакуума.
● удаляем указатели в индексах;
● удаляем строки из таблицы с lazy_vacuum_heap().
![Page 60: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/60.jpg)
lazy_vacuum_heap()
lazy_vacuum_heap() – второй проход по таблице.
Цикл через собранные строки (vacrelstats) – идем только в те страницы, где есть мертвые строки:
● перед началом делаем vacuum_delay_point();
● читаем блок и считаем costs;
● пытаемся взять блокировку для очистки – пропускаем блок, если не удалось;
● чистим страницу с lazy_vacuum_page();
● обновляем Free Space Map.
![Page 61: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/61.jpg)
lazy_vacuum_page()
lazy_vacuum_page() – чистим dead-строки в странице, убираем фрагментацию.
Все изменения в критической секции:
● цикл по dead строкам (внутри страницы);
● отмечаем указатель ItemID как неиспользуемый (LP_UNUSED);
● убираем фрагментацию страницы;
● отмечаем страницу как грязную, пишем в WAL.
Закрываем критическую секцию.
Обновляем Visibility Map.
![Page 62: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/62.jpg)
lazy_scan_heap()
Таблица обработана, VM обновлена.
Обновляем FreeSpaceMap.
Обновление статистики индексов (pg_class).
Пишем в журнал сообщение о проделанной работе.
![Page 63: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/63.jpg)
Конец ?
![Page 64: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/64.jpg)
Что в итоге?
Вакуум всегда должен быть включен.
Дефолтные настройки не оптимальный.
Нагрузка регулируется через cost-based опции.
Wraparound – не так страшен черт...
Вакуум не всегда может вычистить таблицу.
Избегайте длинных транзакций.
![Page 65: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/65.jpg)
Ссылки
Alexey Lesovsky – [email protected]
See slides on SlideShare: http://www.slideshare.net/alexeylesovsky/
PostgreSQL official documentation:
● Vacuum: https://www.postgresql.org/docs/current/static/routine-vacuuming.html
● Autovacuum:
● https://www.postgresql.org/docs/current/static/routine-vacuuming.html#AUTOVACUUM
● https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html
● Progress Reporting: https://www.postgresql.org/docs/devel/static/progress-reporting.html
● PageInspect contrib module: https://www.postgresql.org/docs/current/static/pageinspect.html
![Page 66: PostgreSQL Vacuum: Nine Circles of Hell](https://reader034.vdocuments.pub/reader034/viewer/2022042513/587b36b01a28ab057d8b7347/html5/thumbnails/66.jpg)
AV Launcher AV Worker
Postmaster
Initialization
Shared memory
Initialization
Scan pg_class
Check relations
Do vacuum
Recheck relations
Process relations
Vacuum/Analyze/Wrap ?
Balance costs
Process 1 relation
Open relation
Perform checks
Set Xid limits
Open indexes
Prune HOT chains Freeze tuples
Remove ind entries
Vacuum heap
Vacuum pages
Update FSM, VM
Close indexes
Truncate relation
Update FSMUpdate pg_class
Close relation
Vacuum TOAST ?
Postgres Backend
FREEZE ?
1 2
1
21
1
1
2
yes
FULL ?
CLUSTERyes
no