Оценка производительности SQL

Оптимизация начинается с измеримого симптома, а не с переписывания синтаксиса. Один и тот же запрос зависит от параметров, распределения данных, кэша, конкуренции и версии СУБД.

Порядок расследования

  1. Зафиксировать запрос, параметры и требуемый результат.
  2. Измерить latency, частоту, число возвращаемых строк и влияние на систему.
  3. Получить фактический план (EXPLAIN ANALYZE или аналог) безопасным способом.
  4. Сравнить estimated rows с actual rows.
  5. Найти основную стоимость: scan, join, sort, aggregate, temp spill, network.
  6. Проверить статистику и существующие индексы.
  7. Сделать одно изменение и повторить измерение.

Warning

Команда с фактическим выполнением действительно выполняет запрос. Для изменяющего DML нужен безопасный стенд или осознанная транзакция с rollback; даже она может оставить побочные эффекты вне БД.

Что читать в плане

  • Seq/Table Scan или Index Scan/Seek;
  • алгоритм соединения: nested loop, hash join, merge join;
  • порядок соединений;
  • оцененное и фактическое число строк;
  • количество циклов узла;
  • сортировка и выход за доступную память;
  • чтение страниц/буферов и временных данных;
  • время планирования и исполнения.

Большое расхождение estimated rows и actual rows часто указывает на устаревшую статистику, коррелированные столбцы, неравномерное распределение или параметр-чувствительный план.

Что измерять кроме latency

  • throughput и p95/p99;
  • CPU, logical/physical reads, temporary I/O;
  • ожидания блокировок;
  • количество соединений и round trips;
  • размер результата;
  • частоту запроса: 2 мс × миллион вызовов важнее единичных 200 мс.

Частые причины

  • N+1 запросов;
  • отсутствующий или неподходящий индекс;
  • чтение лишних строк/столбцов;
  • неявное приведение типов;
  • размножение строк до агрегации;
  • пагинация с большим OFFSET;
  • lock contention;
  • неверная оценка селективности.

Проверка результата

Оптимизированный запрос должен быть семантически эквивалентен: сравнивают не только скорость, но и строки, NULL, дубликаты, порядок и поведение при конкуренции.

Связано: Индексы SQL, Селективность SQL, Что лучше подзапросы или JOIN, Кейс фильтр поверх UNION.

Вопросы

Почему одного EXPLAIN мало? Он показывает оценки; фактическое выполнение выявляет реальные строки, циклы и время.

Что означает сильное расхождение estimate/actual? Оптимизатор неправильно оценил кардинальность, поэтому мог выбрать неудачный план.

Всегда ли index scan быстрее seq scan? Нет; при чтении большой доли таблицы последовательный проход дешевле.

Почему p99 важен? Среднее скрывает хвост задержек, который видят пользователи и очереди.

Как доказать улучшение? Сравнить воспроизводимые замеры и корректность до/после на репрезентативных данных.