PostgreSQL - мощный инструмент, но без правильной настройки он быстро превращается в тормозную лошадь. Чаще всего проблемы растут из трех вещей: кривые запросы, отсутствие индексов и стандартные настройки конфига, которые рассчитаны на старый комп. Давайте разберем, что можно сделать прямо сейчас, чтобы база летала.
Без индексов PostgreSQL сканирует таблицу целиком. Это больно. Но ставить индекс на каждую колонку - тоже плохая идея: замедляются вставки и разрастается размер базы.
=, <, >, BETWEEN.=. Если вам нужен поиск по точному совпадению (например, хэш пароля), это ваш вариант.tags text[] или data jsonb, GIN спасет.Пример из жизни. Допустим, у вас таблица заказов:
CREATE INDEX idx_orders_created_at ON orders (created_at);
-- Для поиска по дате это ускорит запрос в 10-50 раз
Но если вы часто ищете по двум полям одновременно, делайте составной индекс:
CREATE INDEX idx_orders_user_date ON orders (user_id, created_at);
-- Порядок важен: сначала селективное поле, потом остальное
Совет: используйте EXPLAIN ANALYZE перед запросом. Если видите Seq Scan на большой таблице - срочно ставьте индекс.
PostgreSQL из коробки настроен на минимальные ресурсы. Если у вас сервер с 8 ГБ ОЗУ, а в конфиге стоит shared_buffers = 128MB - вы теряете производительность.
Пример настройки в postgresql.conf:
shared_buffers = 2GB
work_mem = 16MB
effective_cache_size = 6GB
maintenance_work_mem = 1GB
random_page_cost = 1.1 # если используете SSD
После изменений перезагрузите кластер. Разницу заметите сразу - особенно на сложных запросах с JOIN и сортировками.
PostgreSQL не удаляет строки физически при DELETE или UPDATE. Он помечает их как мертвые. Со временем таблица раздувается, запросы тормозят.
Автовакуум работает по умолчанию, но его настройки часто слабые. Проверьте:
SHOW autovacuum_vacuum_scale_factor; -- по умолчанию 0.2 (20% изменений)
Для активных таблиц лучше уменьшить этот порог:
ALTER TABLE orders SET (autovacuum_vacuum_scale_factor = 0.05);
ALTER TABLE orders SET (autovacuum_vacuum_threshold = 100);
И не забывайте про ANALYZE. Он обновляет статистику для планировщика. Если после массовой вставки запросы стали тормозить - скорее всего, статистика устарела.
ANALYZE orders;
-- Или для всей базы: vacuumdb --analyze -d yourdb
Даже с идеальными индексами можно убить производительность кривым SQL. Вот что я видел чаще всего в продакшене:
WHERE DATE(created_at) = '2024-01-01' убивает индекс. Пишите WHERE created_at >= '2024-01-01' AND created_at < '2024-01-02'.Пример плохого запроса:
SELECT * FROM orders WHERE total > (SELECT AVG(total) FROM orders);
-- Лучше сделать так:
WITH avg_total AS (SELECT AVG(total) AS avg FROM orders)
SELECT * FROM orders, avg_total WHERE orders.total > avg_total.avg;
Разница может быть в разы, если таблица большая.
Если таблица разрастается до сотен гигабайт, индексы перестают помогать. Тут выручает партиционирование - разбивка таблицы на куски по диапазону (по дате, по id).
Пример для таблицы логов:
CREATE TABLE logs (
id SERIAL,
created_at TIMESTAMP NOT NULL,
message TEXT
) PARTITION BY RANGE (created_at);
CREATE TABLE logs_2024_01 PARTITION OF logs
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
CREATE TABLE logs_2024_02 PARTITION OF logs
FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
Теперь запрос с фильтром по дате будет сканировать только одну партицию. Это ускоряет выборку и упрощает удаление старых данных (просто дропаете партицию).
Оптимизация PostgreSQL - это не магия, а система. Если база тормозит, пройдитесь по чеклисту:
Начните с EXPLAIN ANALYZE. Он покажет, где именно база тратит время. Часто проблема оказывается в одной строчке кода, которую вы писали «на скорую руку». Исправьте её - и прирост производительности будет в разы больше, чем от любой настройки конфига.
Комментариев пока нет