Как анализировать DML через EXPLAIN
Как исследовать планы UPDATE, DELETE и INSERT и почему EXPLAIN ANALYZE для изменяющих запросов требует особой осторожности.
PostgreSQLDMLEXPLAINПроизводительностьБезопасность данныхКофе давно остыл. Монитор гипнотизировал Лену мигающим курсором.
— Мучаешь базу? — раздался за спиной голос Макса. Он стоял, прислонившись к дверному косяку с пустой кружкой в руке.
— Это не я, это UPDATE, — вздохнула Лена. — Просто меняет статусы у старых задач. Что тут может быть не так?
— Ты думаешь, это простая операция. А я говорю: твой UPDATE — это приговор производительности.
Лена развернулась на стуле.
— Приговор? Макс, это же не сложный SELECT с кучей JOINов. Это просто UPDATE…
— Ну и что? Прежде чем обновить, база должна найти. А как она ищет? Через планировщик — фактически тем же способом, как если бы выполняла SELECT.
Он подошёл ближе и кивнул на монитор:
— Попробуй EXPLAIN, без ANALYZE. Тогда база просто покажет план, не выполняя сам запрос.
— Хочешь сказать, что EXPLAIN работает и с UPDATE?
— Конечно. Все DML операторы можно анализировать через EXPLAIN.
— И EXPLAIN ANALYZE можно? он же фактически выполняет запрос.
— Можно и EXPLAIN ANALYZE, — кивнул Макс. — Он действительно выполнит UPDATE. На изолированном стенде его иногда оборачивают в транзакцию и завершают ROLLBACK:
BEGIN;EXPLAIN (ANALYZE, BUFFERS)UPDATE tasksSET status = 'archived'WHERE created_at < date '2024-01-01';ROLLBACK;— Но ROLLBACK не делает эксперимент бесплатным и полностью обратимым. Запрос всё равно берёт блокировки, пишет WAL, создаёт нагрузку и может надолго удержать старые версии строк. Значения sequence не откатываются, а пользовательские функции и триггеры могут иметь внешние побочные эффекты. На продакшене такой запуск без отдельной оценки недопустим.
Лена нахмурилась.
— Но это же разовая ручная операция. Не создавать же индекс ради неё?
— Я знаю, что я зануда, — улыбнулся Макс. — Конечно ты права, для единичных действий индекс — только балласт. Просто обратил твое внимание, что анализировать и оптимизировать можно и нужно не только SELECTы.
Он сделал глоток остывшего кофе и добавил:
— Вот взять INSERT. Думаешь, это быстро. А потом выясняется, что на каждую вставку срабатывают триггеры: журналирование, проверки, дополнительная обработка. В EXPLAIN ANALYZE время триггеров видно отдельно, но саму операцию безопаснее исследовать на репрезентативном стенде.
— Аж захотелось посмотреть, как работает INSERT с ON CONFLICT. — задумалась Лена.
— Да, UPSERT тот ещё артист. Сначала проверит конфликт — фактически ищет строку через индекс, — потом решит, вставлять или обновлять. И план все покажет.
— Значит, любая DML-операция…
— …это не только изменение строк, — продолжил Макс. — Нужно понять, как PostgreSQL находит целевые строки, проверяет ограничения и индексы и какие триггеры запускает. Только тогда можно осмысленно ускорять операцию.
Он подмигнул и пошёл к кофемашине.
А Лена, глядя на экран, решила ничего не менять.
Медленный запрос — не приговор, а симптом.
И вообще, оптимизировать стоит не только запросы, но и своё время, и силы.