> Как определить, что запрос в базе тормозит (Go)
Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы
Компании: Employcity
Стек: Go, Java
> Пример ответа
Короткий ответ
Определить тормозящий запрос можно через observability: метрики latency и throughput на уровне SQL, логи медленных запросов, трассировку и профилирование. В Go и Java смотрят на context deadline, пул соединений и время ожидания в очереди. Дальше подтверждают гипотезу через EXPLAIN ANALYZE, pg_stat_statements или аналоги и смотрят на планы выполнения.
Подробное объяснение
На уровне инфраструктуры тормоза проявляются как рост p95 и p99 latency, падение throughput, увеличение времени ожидания соединения из пула и таймауты на клиенте. Важно разделять время в самой базе и время до неё: сеть, DNS, TLS, балансировщик, пул соединений. Внутри базы смотрят на slow query log, pg_stat_statements, performance_schema, wait events и блокировки. Отдельно проверяют план выполнения: seq scan на большой таблице, неверная оценка кардинальности, nested loop на миллионах строк, сортировка на диске, spill в temp files. На уровне приложения тормоза часто вызваны N+1, отсутствием индексов, отсутствием батчинга, слишком большими транзакциями и удержанием соединения во время внешних вызовов. В Go это видно через context, pprof и метрики database/sql, в Java - через Micrometer, HikariCP metrics и JFR.
На практике
Сначала смотрят на дашборды: latency по endpoint, latency по запросу, ошибки, таймауты, размер пула. Потом идут в slow query log и pg_stat_statements, сортируют по total time и mean time. Затем берут конкретный запрос и делают EXPLAIN (ANALYZE, BUFFERS). Проверяют индексы, статистику, блокировки, wait events. В приложении проверяют, не держится ли соединение во время HTTP-вызова, нет ли N+1, не слишком ли большой batch. В Go смотрят на context deadline и на то, не отменяется ли запрос раньше времени. В Java смотрят на HikariCP: active, idle, pending, timeout. Если запрос тормозит только под нагрузкой, проверяют contention, cache miss, autovacuum, checkpoint и репликацию.
Пример кода
GOctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)defer cancel()start := time.Now()rows, err := db.QueryContext(ctx, `SELECT id, emailFROM usersWHERE created_at >= $1ORDER BY created_at DESCLIMIT 100`, since)if err != nil {log.Printf("query failed after %s: %v", time.Since(start), err)return err}defer rows.Close()log.Printf("query took %s", time.Since(start))
JAVAtry (Connection conn = dataSource.getConnection();PreparedStatement ps = conn.prepareStatement("SELECT id, email FROM users WHERE created_at >= ? ORDER BY created_at DESC LIMIT 100")) {ps.setQueryTimeout(1);long start = System.nanoTime();try (ResultSet rs = ps.executeQuery()) {// process}long elapsedMs = (System.nanoTime() - start) / 1_000_000;log.info("query took {} ms", elapsedMs);}
Как отвечать на собеседовании
Сначала назовите уровни диагностики: метрики, логи, трассировка, профилирование, план запроса. Потом объясните, как отделить проблему базы от проблемы приложения и сети. Упомяните pg_stat_statements, slow query log, EXPLAIN ANALYZE, wait events, блокировки. Скажите про пул соединений и context deadline в Go, про HikariCP и JFR в Java. Покажите, что умеете идти от симптома к причине: p99 latency, таймауты, N+1, seq scan, spill, lock contention. В конце добавьте, как проверяете гипотезу и как измеряете улучшение.
Что проверяет интервьюер
Проверяет системное мышление: умеет ли кандидат разделять слои и не путать причину со следствием. Проверяет знание инструментов observability и профилирования. Проверяет понимание планов выполнения, индексов, статистики и блокировок. Проверяет навык работы с пулом соединений и таймаутами в Go и Java. Проверяет умение формулировать гипотезы и подтверждать их данными. Проверяет опыт диагностики под нагрузкой и понимание trade-off между latency и throughput.
Типичные ошибки
Смотреть только на среднее время и игнорировать p95 и p99. Путать время в базе со временем на клиенте. Делать выводы без EXPLAIN ANALYZE. Добавлять индекс без проверки плана и статистики. Держать соединение во время внешнего вызова. Игнорировать пул соединений и его очередь. Не учитывать блокировки и wait events. Забывать про N+1 и батчинг. Оптимизировать запрос, который на самом деле не является узким местом.
> Похожие задачи по Go
Что такое бакет в хэш-таблице
Что ищешь в работе и почему ушел с предыдущего проекта
Что означает ошибка 400 в HTTP?
Что такое протокол HTTP и как он работает
> Похожие задачи по backend
Что такое бакет в хэш-таблице
Что ищешь в работе и почему ушел с предыдущего проекта
Что означает ошибка 400 в HTTP?
Что такое протокол HTTP и как он работает
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью