Как определить, что запрос в базе тормозит
Что проверяют
Умеете ли вы найти медленный запрос по данным, а не по ощущениям, и отличить медленную базу от медленного приложения. Следом обычно спрашивают, что делать, когда запрос найден.
Как отвечать
Идите с двух сторон. Со стороны базы, на примере PostgreSQL:
pg_stat_statements: накопленная статистика по нормализованным запросам. Сортировка поtotal_exec_timeпоказывает, что сильнее всего нагружает базу, поmean_exec_timeчто медленно само по себе, аcallsотличает редкий тяжёлый запрос от частого лёгкого;log_min_duration_statement: пишет в лог каждый запрос дольше порога, например 500 мс. Вместе сauto_explainв лог попадает и план;pg_stat_activity: что выполняется прямо сейчас и сколько. Колонкиwait_event_typeиwait_eventпоказывают, что запрос стоит на блокировке, а не считает;EXPLAIN (ANALYZE, BUFFERS): реальный план с временем по узлам и чтениями с диска. Ищите узлы, где оценка числа строк сильно расходится с фактом.
Со стороны Go-сервиса:
- метрики и трассировка: гистограмма длительности по каждому запросу в Prometheus и спаны OpenTelemetry. В pgx v5 для этого есть интерфейс
QueryTracer. Смотрите p95 и p99, среднее прячет хвосты; - пул соединений:
db.Stats()отдаётWaitCountиWaitDuration. Если они растут, сам запрос быстрый, а горутины стоят в очереди за соединением. Лечится это настройкойSetMaxOpenConnsили поиском незакрытыхrows, которые держат соединения.
Где спотыкаются
Запускают EXPLAIN без ANALYZE и обсуждают оценки как факт. Обратная ошибка: EXPLAIN ANALYZE на UPDATE или DELETE в проде, ведь он реально выполняет запрос. Такое оборачивают в транзакцию с ROLLBACK.
Считают любой Seq Scan проблемой. На маленькой таблице или при низкой селективности полный проход дешевле индекса, и планировщик прав.
Ищут медленный запрос через pprof. CPU-профиль покажет время в коде Go, а ожидание ответа базы в нём почти не видно. Для этого нужны трассировка и статистика самой базы.