Приходилось ли профилировать SQL-запросы и анализировать их выполнение
Что проверяют
Умеете ли вы читать план запроса и понимаете ли, откуда в приложении на Python берутся лишние обращения к базе. Ответ показывает, отделяете ли вы медленный запрос от медленного кода вокруг него. Следом дают конкретный план на разбор или спрашивают, почему индекс есть, а не используется.
Как отвечать
Ответ делится надвое: сторона базы и сторона ORM.
- план: в PostgreSQL это
EXPLAIN (ANALYZE, BUFFERS). БезANALYZEвы видите только оценки планировщика, с ним запрос реально выполняется, поэтому изменяющие запросы гоняют в транзакции с откатом; - что искать: расхождение оценки и фактического числа строк (устаревшая статистика, помогает
ANALYZEтаблицы),Seq Scanпо большой таблице,Nested Loopс тысячами повторов, сортировку, ушедшую на диск из-за нехваткиwork_mem, крупноеRows Removed by Filter; - поиск кандидатов: расширение
pg_stat_statementsдаёт топ по суммарному времени,auto_explainкладёт планы медленных запросов в лог,log_min_duration_statementловит сам факт; - правки: составной индекс с правильным порядком колонок, частичный индекс под постоянное условие, покрывающий с
INCLUDE, переход отOFFSETк пагинации по ключу, функциональный индекс, если в условии есть вычисление над колонкой; - сторона Python: в SQLAlchemy проблема N+1 лечится
selectinloadиjoinedload, аlazy="raise"в тестах ловит ленивую подгрузку до продакшена. В Django те же роли уselect_relatedиprefetch_related, план доступен черезQuerySet.explain(), а тест со счётчиком запросов не даёт регрессии вернуться.
Опыта немного, скажите честно: смотрели медленные запросы в логах, добавляли индексы, глубоким разбором планов не занимались. Это лучше выдуманных процентов ускорения.
Где спотыкаются
Делают выводы по EXPLAIN без ANALYZE. Оценка и реальность расходятся как раз в проблемных запросах, ради которых всё и затевалось.
Вешают отдельный индекс на каждую колонку из WHERE. Запись дорожает, размер базы растёт, а нужный составной индекс так и не появляется.
Профилируют на пустой тестовой базе. На сотне строк планировщик честно выберет последовательное чтение, и измерять там нечего.