
В мире PostgreSQL, как и в автоспорте, не существует единой идеальной стратегии для всех трасс. Выбор интервала контрольных точек (checkpoint_timeout) — это пит-стоп: можно заезжать часто для максимальной скорости на прямых, но рискуя потерять время на самом заезде, или реже — для стабильного и предсказуемого ритма всей гонки. Всё зависит от типа «трассы» — характера нагрузки на вашу базу данных.
Глоссарий терминов | Postgres DBA | Дзен
Методология исследования
Тестовая среда, инструменты и конфигурация СУБД:
СУБД: PostgreSQL 17
Тестовые базы данных:
Вариант нагрузки №1 - "Демобаза 2.0" (большой размер, сложная схема)
Вариант нагрузки №2 - Тестовая база pgbench (большой размер, простая схема)
Условия тестирования: параллельная нагрузка от 7 до 22 сессий (количество сессий для тестового сценария определяется согласно весовому коэффициенту).
Вариант нагрузки №1
Высокая нагрузка на CPU
Высокая читающая нагрузка
Низкая пишущая нагрузка.
Тестовый сценарий-1 (SELECT BY PK)
SELECT * FROM bookings.airports_data WHERE airport_code = ( SELECT airport_code FROM bookings.airports_data ORDER BY random() LIMIT 1 );
Тестовый сценарий-2 (GROUP BY)
WITH random_airplanes AS ( SELECT airplane_code FROM bookings.airplanes_data ORDER BY random() LIMIT (random() * 9 + 1)::int -- От 1 до 10 значений ) SELECT s.fare_conditions, COUNT(*) as seat_count, COUNT(DISTINCT s.airplane_code) as airplane_types FROM bookings.seats s WHERE s.airplane_code IN (SELECT airplane_code FROM random_airplanes) GROUP BY s.fare_conditions ORDER BY seat_count DESC;
Тестовый сценарий-3 (ORDER BY)
Новости Статьи Видео Ролики Сохранённое Видеоигры Детям Всё о Дзене Вакансии Дзен на iOS и Android Ещё Postgres DBA ваш канал --Тестовый сценарий-3 (ORDER BY) SELECT book_ref, book_date, total_amount, EXTRACT(DAY FROM book_date) as booking_day FROM bookings.bookings WHERE total_amount > 0 ORDER BY book_date LIMIT (random() * 499 + 1)::int; -- От 1 до 500 записей
Тестовый сценарий-4 (JOIN)
WITH random_departures AS ( SELECT airport_code FROM bookings.airports_data ORDER BY random() LIMIT (random() * 9 + 1)::int ), random_validity_date AS ( SELECT date_trunc('day', lower(validity) + (random() * EXTRACT(EPOCH FROM (upper(validity) - lower(validity)))) * interval '1 second' ) as random_date FROM bookings.routes WHERE validity IS NOT NULL AND upper(validity) > lower(validity) + interval '7 days' ORDER BY random() LIMIT 1 ) SELECT r.route_no, r.departure_airport, a_dep.city->>'en' as departure_city, r.arrival_airport, a_arr.city->>'en' as arrival_city, r.duration, r.days_of_week FROM bookings.routes r JOIN bookings.airports_data a_dep ON r.departure_airport = a_dep.airport_code JOIN bookings.airports_data a_arr ON r.arrival_airport = a_arr.airport_code CROSS JOIN random_validity_date rvd WHERE r.departure_airport IN (SELECT airport_code FROM random_departures) AND r.validity @> rvd.random_date AND array_length(r.days_of_week, 1) > 0 ORDER BY r.departure_airport, r.route_no LIMIT 300;
Тестовый сценарий-5 (INSERT + DELETE)
-- INSERT тестовой брони INSERT INTO bookings.bookings(book_ref, book_date, total_amount) VALUES (test_book_ref, now(), 0.0) ON CONFLICT (book_ref) DO NOTHING; PERFORM pg_sleep(0.02); -- DELETE тестовой брони DELETE FROM bookings.bookings WHERE book_ref LIKE 'scenario5-TEST%' AND book_date < now() - interval '5 minute';
Тестовый сценарий-6 (UPDATE)
WITH completed_flights AS ( SELECT DISTINCT flight_id FROM bookings.flights WHERE status = 'Arrived' AND actual_arrival < ( SELECT actual_arrival FROM bookings.flights WHERE actual_arrival IS NOT NULL ORDER BY random() LIMIT 1 ) LIMIT 5 ) UPDATE gen.seats_remain sr SET available = ( SELECT count(*) FROM bookings.seats s JOIN bookings.routes r ON r.airplane_code = s.airplane_code JOIN bookings.flights f ON f.route_no = r.route_no WHERE f.flight_id = sr.flight_id ) FROM completed_flights cf WHERE sr.flight_id = cf.flight_id;
Весовые коэффициенты тестовых сценариев
scenario1 = 1.0 scenario2 = 1.0 scenario3 = 1.0 scenario4 = 1.0 scenario5 = -1.0 #Неконкурентная нагрузка = 1 соединение scenario6 = 0.5
Вариант нагрузки №2
Низкая нагрузка на CPU
Низкая читающая нагрузка
Высокая пишущая нагрузка.
Тестовый сценарий-1 (SELECT)
SELECT MAX(aid) INTO max_i FROM pgbench_accounts ; SELECT MIN(aid) INTO min_i FROM pgbench_accounts ; current_aid = floor(random() * (max_i - min_i + 1)) + min_i ; select br.bbalance into test_rec from pgbench_branches br join pgbench_accounts acc on (br.bid = acc.bid ) where acc.aid = current_aid ;
Тестовый сценарий-2 (UPDATE)
UPDATE pgbench_accounts SET abalance = abalance + current_delta WHERE aid = current_aid ; UPDATE pgbench_tellers SET tbalance = tbalance + current_delta WHERE tid = current_tid ; UPDATE pgbench_branches SET bbalance = bbalance + current_delta WHERE bid = current_bid ;
Тестовый сценарий-3 (INSERT)
FOR counter IN 1..1000 LOOP INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES ( current_tid , current_bid , current_aid , current_delta , CURRENT_TIMESTAMP ); END LOOP;
Весовые коэффициенты тестовых сценариев
scenario1 = 1.0 scenario2 = 0.5 scenario3 = 0.5
Исходные данные экспериментов:
Вариант нагрузки-1:Часть-1:СУБД.
Вариант нагрузки-1:Часть-2:Инфраструктура.
Вариант нагрузки-2:Часть-1:СУБД.
Вариант нагрузки-2:Часть-2:Инфраструктура.
Вариант нагрузки №1 - анализ с точки зрения производительности СУБД
checkpoint_timeout=1 минута:
Преимущества: Наивысшая пиковая производительность (2 599 957)
Недостатки:
Наиболее выраженное снижение производительности со временем
Сильная обратная корреляция между скоростью и ожиданиями (-0.79)
Высокая нагрузка на LockManager
checkpoint_timeout=15 минут:
Преимущества: Более плавное снижение производительности
Недостатки:
Наибольшие максимальные ожидания (10 128)
Появление конкуренции за буферы (BufferMapping)
Наихудшая минимальная производительность (140)
checkpoint_timeout=30 минут:
Преимущества: Наиболее стабильные показатели
Недостатки:
Наименьшая максимальная производительность (1 888 191)
Средние показатели по всем метрикам
Рекомендации для заданной нагрузки
Для варианта нагрузки №1 (высокая CPU, высокая читающая нагрузка, низкая пишущая):
Оптимальное значение checkpoint_timeout: 15-30 минут
Более редкие checkpoint снижают конкуренцию за ресурсы
Уменьшают нагрузку на подсистему ввода-вывода
Обеспечивают более стабильную производительность
Общ��й вывод
Параметр checkpoint_timeout оказывает значительное влияние на производительность СУБД при заданной нагрузке. Для варианта с высокой читающей и низкой пишущей нагрузкой рекомендуются более редкие checkpoint (15-30 минут), что обеспечивает более стабильную производительность и снижает конкуренцию за системные ресурсы.
Вариант нагрузки №2 - анализ с точки зрения производительности СУБД
Положительные эффекты увеличения интервала:
Более высокая начальная производительность:
При checkpoint_timeout=15-30мин производительность на 44% выше, чем при 1 мин
Меньше накладных расходов на частые checkpoint-ы
Негативные эффекты увеличения интервала:
Более быстрая деградация производительности:
Производительность падает быстрее при длинных интервалах checkpoint
Рост максимальных ожиданий:
При checkpoint_timeout=30мин ожидания достигают 123 362 (против 112 965 при 1 мин)
Усиление корреляции между скоростью и ожиданиями:
Корреляция усиливается с -0.53 до -0.94, что указывает на более сильную зависимость производительности от ожиданий
Механизмы влияния checkpoint_timeout на пишущую нагрузку
При коротком интервале (1 мин):
Частые checkpoint-ы → меньше данных для записи за раз
Меньший объем WAL-файлов между checkpoint-ами
Более равномерная нагрузка на IO, но больше накладных расходов
Меньше блокировок extend (выше доля в общем объеме, но меньше абсолютное значение)
При длинном интервале (15-30 мин):
Редкие checkpoint-ы → накопление больших объемов изменений
Более интенсивные всплески записи при checkpoint-ах
Увеличение объема DataFileRead (чтение "грязных" страниц для записи)
Рост конкуренции за ресурсы (LWLock, BufferContent)
Рекомендации для заданного варианта нагрузки
Для высокой пишущей нагрузки с низким чтением:
Оптимальный диапазон checkpoint_timeout: 5-10 минут
Компромисс между накладными расходами (1 мин) и всплесками нагрузки (15-30 мин)
Позволяет снизить частоту checkpoint-ов без чрезмерного накопления изменений
Выводы
Checkpoint_timeout существенно влияет на производительность при высокой пишущей нагрузке, определяя баланс между накладными расходами и объемом единовременной записи.
Экстремальные значения (1 мин и 30 мин) неоптимальны:
1 мин: слишком высокие накладные расходы, низкая начальная производительность
30 мин: быстрая деградация, высокие пиковые ожидания
Наиболее стабильное поведение наблюдается при checkpoint_timeout=15 мин, хотя и с быстрой деградацией производительности.
Основной лимитирующий фактор — IO-ожидания (DataFileRead), что необычно для пишущей нагрузки и указывает на необходимость оптимизации процессов чтения при checkpoint-ах.
Рекомендуется тестирование промежуточных значений checkpoint_timeout (5-10 мин) для нахождения оптимального баланса для конкретной конфигурации и нагрузки.
Итоговый вывод с точки зрения производительности СУБД
Чем выше интенсивность пишущей нагрузки на СУБД тем более оптимальнее будет уменьшение интервала между контрольными точками.
Вариант нагрузки №1 - анализ производительности ОС
Влияние параметра checkpoint_timeout
Нагрузка на CPU:
Увеличение
checkpoint_timeoutс 1 до 15 минут снижает нагрузку на CPU (очередь процессов уменьшается с 98.21% до 79.57%).Дальнейшее увеличение до 30 минут ухудшает показатель (88.89%).
Использование памяти:
Увеличение
checkpoint_timeoutснижает дефицит свободной RAM (с 100% до 77.78%).Наиболее эффективно значение 30 минут.
Итог
Параметр checkpoint_timeout влияет на баланс между нагрузкой на CPU и использованием памяти. Для заданного варианта нагрузки оптимальным является значение 15 минут, которое обеспечивает наименьшую нагрузку на CPU при приемлемом использовании памяти. Однако системные ресурсы (CPU и RAM) недостаточны для данной нагрузки, что требует дополнительной оптимизации или масштабирования.
Вариант нагрузки №2 - анализ производительности ОС
Параметр checkpoint_timeout почти не влияет на IO-проблемы:
Во всех трёх экспериментах наблюдается одинаково высокий уровень ожиданий IO (wa).
Количество процессов в состоянии
uninterruptible sleep(ожидание IO) стабильно превышает количество ядер CPU.Это указывает на системную проблему с подсистемой IO, не связанную напрямую с частотой контрольных точек.
Увеличение checkpoint_timeout снижает нагрузку на CPU от LWLock:
В экспери��енте-1 (1 мин) корреляция LWLock-sy = 0.7721 (ALARM).
В эксперименте-2 (15 мин) корреляция снижается до 0.4114 (INFO).
В эксперименте-3 (30 мин) — 0.6755 (WARNING).
Вывод: Более редкие контрольные точки снижают конкуренцию за лёгковесные блокировки (LWLock) в ядре.
Память — узкое место:
Во всех экспериментах свободной памяти < 5%.
Несмотря на это, свопинг не используется, что может указывать на:
Неэффективное использование кэширования/буферизации.
Возможную утечку памяти или недостаточный размер RAM для рабочей нагрузки.
Итог
Параметр checkpoint_timeout не является ключевым фактором для производительности ОС при заданном профиле нагрузки (низкий CPU, низкое чтение, высокая запись). Основные проблемы связаны с подсистемой IO и нехваткой памяти. Увеличение checkpoint_timeout до 15–30 минут может снизить нагрузку на CPU от LWLock, но не решит фундаментальных проблем с IO и памятью.
Итоговый вывод с точки зрения производительности ОС
Для данной инфраструктуры виртуальной машины и заданных вариантов нагрузки, параметр checkpoint_timeout не является ключевым фактором для производительности инфраструктуры из-за неоптимальной настройки IO и RAM.
