На что обращать внимание в EXPLAIN ANALYZE для оценки производительности запроса
Что проверяют
Умеете ли вы читать план запроса и находить настоящее узкое место, а не угадывать. Для питониста вопрос почти всегда двойной: разобрать план и понять, что этот запрос вообще породила ORM и выполняется он не один раз.
Как отвечать
Перечислите, на что смотрите в выводе PostgreSQL:
- расхождение оценки и факта:
rows=противactual rows=. Если планировщик ошибся на порядки, чинить надо статистику, а не запрос; loops: время узла показано на один проход, его надо умножать на число проходов. Так и находитсяNested Loopс тысячами итераций;- собственное время узла, а не суммарное сверху: дорогой узел обычно прячется в глубине;
- буферы через
EXPLAIN (ANALYZE, BUFFERS):shared readэто реальные чтения,shared hitэто попадания в кэш; - маркеры проблем:
Rows Removed by Filterв тысячах строк, сортировка сSort Method: external merge Disk,Heap Blocks: lossy, рост числа батчей уHash Join; Planning TimeпротивExecution Time: у короткого запроса планирование может занимать больше самого выполнения.
Со стороны Python добавьте, что план не покажет проблему N плюс один: её видно только в логе запросов, через echo у SQLAlchemy или встроенные средства отладки Django.
Где спотыкаются
Считают Seq Scan приговором. На маленькой таблице или при выборке значительной части строк последовательное чтение дешевле индексного доступа, и планировщик прав.
Игнорируют loops и читают время узла как итоговое. Отсюда вывод «тут всего доли миллисекунды», хотя этот узел отработал десять тысяч раз и съел весь запрос.
Забывают, что EXPLAIN ANALYZE действительно выполняет запрос, включая изменения данных, поэтому на проде его оборачивают в транзакцию с откатом. И что план на локальной базе с другим объёмом и статистикой не совпадёт с боевым.