Оптимизация оперативной памяти PostgreSQL: shared_buffers, work_mem и maintenance_work_mem
- Процессы PostgreSQL аварийно завершаются OOM Killer при выполнении сложных аналитических запросов.
- Запросы выполняют сортировку на диске (временные файлы в
pgsql_tmp) вместо оперативной памяти. - Высокая дисковая задержка (I/O wait) из-за неоптимального размера
shared_buffers. - Долгие операции создания индексов (
CREATE INDEX) и очистки (VACUUM).
1. Базовые формулы расчета параметров памяти
shared_buffers: 25% от общего объема RAM (для выделенного сервера БД). На Linux серверах с RAM > 64GB обычно ограничивается 16–32GB.effective_cache_size: 50–75% от общего объема RAM (подсказка планировщику об объеме дискового кэша ОС).maintenance_work_mem: 5–10% от RAM (до 2GB на процесс для операций VACUUM, CREATE INDEX, ADD FOREIGN KEY).work_mem: рассчитывается индивидуально:((Total_RAM - shared_buffers) * 0.8) / (max_connections * 3).
2. Конфигурация в postgresql.conf
# Пример для сервера с 32GB RAM и max_connections = 100
shared_buffers = 8GB
effective_cache_size = 24GB
maintenance_work_mem = 2GB
work_mem = 64MB
# Включение Huge Pages для снижения накладных расходов TLB
huge_pages = try3. Настройка параметров ядра Linux (sysctl)
Создайте файл /etc/sysctl.d/99-postgresql-mem.conf:
vm.overcommit_memory = 2
vm.overcommit_ratio = 80
vm.swappiness = 1
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10sysctl --system4. Применение настроек без остановки сервера
SELECT pg_reload_conf();Примечание: изменение shared_buffers и huge_pages требует полного перезапуска службы PostgreSQL (systemctl restart postgresql).
Частые вопросы (FAQ)
Почему work_mem выделяется не один раз на соединение, а на каждый узел плана запроса?
Сложный SQL-запрос с несколькими операциями ORDER BY, DISTINCT, HASH JOIN может одновременно задействовать несколько блоков work_mem. При значении 64MB и 4 узлах сортировки один запрос потребит 256MB RAM.
Почему не стоит ставить shared_buffers больше 40% RAM в Linux?
PostgreSQL использует двойное кэширование: собственные буферы (shared_buffers) и системный Page Cache ядра Linux. Слишком большой shared_buffers снижает эффективность Page Cache и увеличивает накладные расходы на контрольные точки (checkpoints).