Как определить, что запрос в базе тормозит
Что проверяют
Умеете ли вы найти медленный запрос по данным, а не по ощущениям, и отличаете ли медленный запрос от медленного доступа к базе. Следом обычно спрашивают: запрос нашли, что делаете дальше.
Как отвечать
Идите от симптома к причине, по слоям:
- метрики приложения: Spring Boot Actuator с Micrometer даёт время запросов и метрики пула HikariCP. Рост
hikaricp.connections.pendingзначит, что потоки ждут соединение, а не выполнение SQL; - трассировка: OpenTelemetry Java agent показывает спаны JDBC внутри запроса пользователя, и видно, какой SQL съел время;
- логирование со стороны Java: datasource-proxy или p6spy пишут SQL с длительностью, у Hibernate есть логирование запросов медленнее заданного порога. Здесь же ловится N+1, когда медленный не один запрос, а сотня быстрых;
- база, PostgreSQL:
log_min_duration_statementпишет в лог всё, что дольше порога,pg_stat_statementsдаёт суммарное и среднее время по нормализованным запросам,pg_stat_activityпоказывает текущие запросы, ихwait_eventи сессииidle in transaction. Для MySQL это slow query log иperformance_schema; - план:
EXPLAIN (ANALYZE, BUFFERS)на реальных параметрах. Смотрите наSeq Scanпо большой таблице, расхождение оценки строк с фактом,Nested Loopпо тысячам строк, сортировку на диск.
Дальше разделите причины: нет подходящего индекса, устаревшая статистика (ANALYZE), ожидание блокировки, нехватка соединений в пуле, лишние данные из-за SELECT * или отсутствия пагинации.
Где спотыкаются
Сразу предлагают «добавить индекс», не посмотрев план. Часто проблема в N+1 или в блокировке, и индекс ничего не изменит.
Запускают EXPLAIN без ANALYZE на тестовой базе с сотней строк. Планировщик на маленьких данных выбирает другой план, и вывод получается ложным.
Не отделяют время в базе от времени в приложении. Запрос в базе выполняется за 5 мс, а в Java занимает секунду, потому что поток полсекунды ждёт свободное соединение.