Урок 01

Как БД влияет на скорость приложения

Роль БД

Что происходит:

  • Каждый запрос — SQL.
  • Тяжёлый SELECT блокирует.
  • Много запросов — сеть.
  • Много соединений — CPU БД.

Что даёт:

  • 70–90% времени запроса — БД.
  • БД — главный bottleneck.
  • Оптимизация БД — самый большой win.

Правило: хочешь ускорить приложение — начни с БД.

Что тормозит БД

Запросы:

  • N+1.
  • Без индексов.
  • Тяжёлые JOIN.
  • Полные сканы.
  • *SELECT .

Схема:

  • Отсутствие индексов.
  • Неверные типы.
  • Денормализация без причины.
  • Нет партиционирования.

Инфра:

  • Мало RAM.
  • Медленный диск.
  • Много соединений.
  • Один сервер.

Правило: запросы, потом схема, потом инфра.

Метрики

Что смотреть:

  • Query time — p95.
  • Rows scanned — сколько просмотрено.
  • Rows returned — сколько нужно.
  • Index usage — используются ли.
  • Cache hit — попадания.
  • Connections — активные.
  • Locks — блокировки.

Правило: если rows scanned >> rows returned — индекс нужен.

Роль индексов

Что дают:

  • Быстрый поиск.
  • Быстрая сортировка.
  • Ускорение JOIN.
  • Ускорение агрегатов.

Что стоят:

  • Место на диске.
  • Замедление INSERT/UPDATE.
  • Сложность поддержки.

Правило: индекс — баланс между чтением и записью.

Как читать EXPLAIN

PostgreSQL:

EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'a@b.com';

Что видно:

  • Seq Scan — плохо на большой таблице.
  • Index Scan — хорошо.
  • Bitmap Heap Scan — хорошо.
  • Nested Loop — для малых.
  • Hash Join — для больших.

Правило: Seq Scan на 1M строк — проблема.

Rows estimate

Проблема: планировщик ошибается.

Пример:

rows=1 (actual=100000)

Что делать:

  • ANALYZE таблицы.
  • Увеличить statistics.
  • Проверить индексы.

Правило: неверная оценка — плохой план.

Соединения

Проблема: много новых соединений.

Что даёт:

  • CPU на setup.
  • Память на каждый.
  • Медленный TLS.

Решение: connection pooling.

Правило: pool — обязателен на высоких RPS.

Блокировки

Что бывает:

  • Row lock — ждут.
  • Table lock — стоп.
  • Deadlock — откат.

Как найти:

SELECT * FROM pg_stat_activity WHERE wait_event_type = 'Lock';

Правило: длинные транзакции — источник блокировок.

Cache hit

Что важно:

  • Shared buffers — кэш БД.
  • Hit rate > 99% — хорошо.
  • < 95% — мало RAM.

Как посмотреть:

SELECT sum(blks_hit) / sum(blks_hit + blks_read) AS hit_rate
FROM pg_stat_database;

Правило: hit rate < 99% — увеличить shared_buffers.

Slow queries

Что смотреть:

  • Лог БД.
  • pg_stat_statements.
  • Pulse / Telescope.

Правило: топ-10 медленных — план оптимизации.

pg_stat_statements

Установка:

CREATE EXTENSION pg_stat_statements;

postgresql.conf:

shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements.max = 10000
pg_stat_statements.track = all

Запрос:

SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;

Что даёт: топ по суммарному времени.

Правило: pg_stat_statements — обязателен.

MySQL: performance_schema

SELECT * FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC LIMIT 20;

Что даёт: аналогично pg_stat_statements.

Правило: включить в my.cnf.

Подход

Порядок:

  1. Измерить — p95, slow queries.
  2. Найти топ-10.
  3. EXPLAIN каждый.
  4. Индексы / переписать.
  5. Измерить снова.

Правило: не угадывать — EXPLAIN.

Что важно в 2026

  • PostgreSQL 16+.
  • pgBouncer — pooling.
  • Реплики — read scale.
  • Партиционирование — для больших.
  • pgvector — для AI.
  • Citus — для шардирования.

Правило: PostgreSQL — дефолт для новых проектов.

С чего начать

Чек-лист:

  • Включить pg_stat_statements.
  • Собрать топ-20 slow queries.
  • EXPLAIN каждую.
  • Добавить индексы где нет.
  • Проверить hit rate.
  • Настроить shared_buffers.
  • Установить pgBouncer.

Практика

1. Включите pg_stat_statements.

2. Соберите топ-20 по времени.

3. Прогоните EXPLAIN на топ-5.

4. Найдите Seq Scan на больших.

5. Добавьте 3 индекса.

6. Замерьте до/после.

7. Проверьте hit rate.

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

Частые ошибки

1. Оптимизировать без метрик:

Не то место

Решение: pg_stat_statements.

2. Игнорировать EXPLAIN:

Гадание

Решение: EXPLAIN ANALYZE.

3. Индекс на всё:

Замедляет запись

Решение: только нужные.

4. Мало shared_buffers:

Низкий hit rate

Решение: 25% RAM.

5. Много соединений:

CPU БД

Решение: pgBouncer.

6. Долгие транзакции:

Блокировки

Решение: короткие.

7. Без мониторинга:

Деградация

Решение: Pulse + pg_stat.

8. Одна БД на всё:

Нет масштаба

Решение: реплики.

Итог

  • БД — 70–90% времени.
  • Запросы — первый шаг.
  • EXPLAIN — обязателен.
  • Индексы — где Seq Scan.
  • pg_stat_statements — топ.
  • Shared buffers — 25% RAM.
  • pgBouncer — pooling.
  • Метрики — до и после.
  • Hit rate > 99%.
  • Порядок: запросы → схема → инфра.

Дальше — оптимизация JOIN и подзапросов в Laravel.