Вебторика
Главная/Журнал/Архитектура

PostgreSQL: 10 частых проблем в проектах

Типичные ошибки в схемах, запросах и настройках PostgreSQL. Что чинить в первую очередь и какой эффект это даёт.

Архитектура5 минутКоманда ВебторикаОпубликовано 24 августа 2026 г.
PostgreSQLпроизводительностьиндексы

Проблемы повторяются из проекта в проект. 10 самых частых — с оценкой эффекта.

1. Отсутствие индексов на внешние ключи

orders.customer_id без индекса. Любая выборка «заказы клиента X» — полный перебор. На 100 000 заказов это 200 мс вместо 2. Исправление: CREATE INDEX ON orders(customer_id). Эффект: ×50–100.

2. N+1 запросы

ORM делает N+1 запросов вместо одного с JOIN. Типично в NestJS + TypeORM или Prisma. Решение: include / with / relations либо явный JOIN. Эффект: ×10–50 на списках.

3. Индексы на низкоселективных полях

Индекс на is_active (boolean) или status (5 значений) бесполезен — планировщик всё равно выберет последовательное сканирование. Плюс замедляет INSERT/UPDATE. Решение: удалить, при необходимости — частичный индекс (WHERE is_active = true).

4. Слишком много индексов

15 индексов на таблицу с 20 полями. Каждый UPDATE обновляет все. На таблице заказов критично. Решение: аудит pg_stat_user_indexes, удаление неиспользуемых (idx_scan = 0).

5. Отсутствие партиционирования на больших таблицах

Таблица журналов на 50 млн строк. DELETE старых записей — часы, VACUUM не справляется. Решение: партиционирование по дате (RANGE), автоматическое удаление старых партиций. DELETE превращается в DETACH PARTITION за миллисекунды.

6. Неправильные типы данных

VARCHAR(255) вместо TEXT, CHAR(1) для статуса, JSON вместо нормализованных полей. Миграция через ADD COLUMN + UPDATE + DROP.

7. VACUUM и autovacuum

По умолчанию autovacuum слишком ленивый. На активных таблицах раздутие достигает 50%+. Запросы замедляются в разы. Решение: autovacuum_vacuum_scale_factor для активных таблиц (0.05 вместо 0.2). Периодический pg_repack.

8. Ненастроенный shared_buffers

По умолчанию 128 MB. На сервере с 32 GB RAM — катастрофа, кэш не работает. Решение: shared_buffers = 25% RAM, effective_cache_size = 50–75% RAM. Эффект: ×2–5 на запросах, ограниченных диском.

9. Слишком много соединений

PostgreSQL плохо работает с 500+ соединениями. Каждое — процесс, переключение контекста съедает CPU. Решение: PgBouncer в режиме пула транзакций + max_connections до 100. Эффект: ×3–5.

10. Отсутствие мониторинга

Без pg_stat_statements не видно, какие запросы на самом деле медленные. Все оптимизации — наугад. Решение: включить расширение, панель в Grafana, оповещение при 95-м процентиле больше 100 мс.

С чего начинать

  1. Включить pg_stat_statements.
  2. Найти топ-10 по total_time.
  3. Посмотреть EXPLAIN ANALYZE.
  4. Добавить недостающие индексы.
  5. Исправить N+1.
  6. Настроить параметры сервера.
  7. Настроить autovacuum.
  8. Партиционирование.
  9. PgBouncer.
  10. Мониторинг.

Выводы

PostgreSQL умеет работать быстро, но не «из коробки». 80% проблем — индексы, N+1 и параметры сервера. Прежде чем добавлять кэш или горизонтальное масштабирование — пройдитесь по чек-листу.

Читать дальше

Оценка за 1 рабочий день

Стоимость и план реализации — по заявке.