Какая команда помогает понять, что происходит при запросе к базе данных для поиска узких мест по производительности
Что проверяют
Умеете ли вы найти медленный запрос и доказать, почему он медленный, а не гадать по коду. Для Go-разработчика следом почти всегда спрашивают, как отличить медленный запрос от проблемы в самом приложении, например от исчерпанного пула соединений.
Как отвечать
Главная команда EXPLAIN, и её варианты стоит сразу развести (на примере PostgreSQL):
EXPLAIN: план без выполнения, только оценки планировщика по статистике;EXPLAIN ANALYZE: запрос выполняется по-настоящему, в плане появляются фактическое время и число строк на каждом узле. ДляUPDATEиDELETEего запускают внутриBEGIN ... ROLLBACK;BUFFERS: сколько страниц прочитано из кеша и с диска. В PostgreSQL 18 выводится вместе сANALYZEпо умолчанию, в старых версиях его пишут явно.
В плане ищите расхождение ожидаемых и фактических rows (устаревшая статистика, лечится ANALYZE таблицы), Seq Scan по большой таблице при селективном условии, Nested Loop с тысячами итераций и сортировку, ушедшую на диск (external merge). В MySQL свой EXPLAIN ANALYZE есть начиная с 8.0.18.
Но EXPLAIN разбирает запрос, который вы уже подозреваете. Найти подозреваемых помогают pg_stat_statements (топ по суммарному времени), log_min_duration_statement и auto_explain, который пишет в лог планы медленных запросов прямо с прода.
Со стороны Go добавьте две вещи. db.Stats() у database/sql отдаёт WaitCount и WaitDuration: если они растут, запросы ждут свободное соединение, и дело в SetMaxOpenConns, а не в индексах. В pgx v5 можно подключить QueryTracer и отправлять длительность каждого запроса в метрики или в трейсинг через OpenTelemetry.
Где спотыкаются
Запускают EXPLAIN ANALYZE на DELETE в проде, забыв, что запрос при этом реально выполнится.
Смотрят план на локальной базе со сотней строк. На маленькой таблице планировщик выберет Seq Scan, и выводы на прод не перенесутся.
Ищут причину только в SQL, хотя в Go частая беда это незакрытые rows. Без rows.Close() соединение не возвращается в пул, и со временем всё приложение встаёт в ожидании.