Что делает команда `EXPLAIN` в базах данных и для чего она нужна?

Ответ

Команда EXPLAIN в СУБД используется для получения плана выполнения SQL-запроса, который строит оптимизатор базы данных. Это ключевой инструмент для анализа и оптимизации производительности запросов.

Основные задачи, которые решает EXPLAIN:

  1. Выявление узких мест: Показывает, какие части запроса выполняются неэффективно.
  2. Анализ использования индексов: Помогает понять, используются ли существующие индексы, и нужны ли новые.
  3. Оценка стоимости запроса: Демонстрирует, какие операции являются самыми "дорогими" (например, полное сканирование таблицы — Seq Scan).

Для получения не только предполагаемого, но и фактического плана выполнения с реальным временем и количеством строк, используется EXPLAIN ANALYZE.

Пример для PostgreSQL:

-- Показывает предполагаемый план
EXPLAIN SELECT * FROM users WHERE id = 42;

-- Выполняет запрос и показывает фактический план
EXPLAIN ANALYZE SELECT * FROM users WHERE id = 42;

Пример вывода:

Index Scan using users_pkey on users  (cost=0.15..8.17 rows=1 width=72) (actual time=0.021..0.022 rows=1 loops=1)
  Index Cond: (id = 42)
Planning Time: 0.078 ms
Execution Time: 0.043 ms

Ключевые параметры в выводе:

  • cost: Оценочная стоимость операции в условных единицах.
  • rows: Ожидаемое количество строк.
  • actual time: Фактическое время выполнения (при использовании ANALYZE).
  • scan type: Тип сканирования (Seq Scan — плохо, Index Scan — хорошо).

В Go для анализа плана можно выполнить такой запрос через database/sql и проанализировать его текстовый вывод.

Ответ 18+ 🔞

Слушай, смотри, вот эта команда EXPLAIN — это же просто волшебная палочка, когда твоя база данных начинает тупить, как старый дед на лавочке. По сути, это ты заглядываешь оптимизатору СУБД прямо в мозги и смотришь, какой план атаки он придумал для твоего SQL-запроса. Без этого ты просто пальцем в небо тыкаешь, почему всё тормозит.

Зачем это, блядь, нужно?

  1. Найти говнокод в запросе. Всё покажет: где он таблицу целиком читает, вместо того чтобы по индексу пройтись. Сразу видно, где собака зарыта, а точнее, где она насрала посреди кода.
  2. Понять, работают ли индексы. Индексы ты накрутил, а они, сука, не используются! EXPLAIN тебе это красной линией подчеркнёт. Или наоборот, покажет, что без нового индекса тут — просто писец, а не запрос.
  3. Оценить, насколько запрос «тяжёлый». Там есть стоимость (cost), она тебе намекнёт: «чувак, эта операция — просто овердохуища ресурсов сожрёт».

А если хочешь не просто план посмотреть, а реальные цифры — сколько времени и строк на самом деле было — то надо крикнуть EXPLAIN ANALYZE. Он запрос выполнит и тебе факты в лицо положит. Без ANALYZE — это как теория, а с ним — уже суровая практика, иногда такая, что волосы дыбом встают.

Вот, смотри, как в PostgreSQL это выглядит:

-- Просто план, запрос не выполняется
EXPLAIN SELECT * FROM users WHERE id = 42;

-- А вот это уже по-взрослому: выполнит и всё разжуёт
EXPLAIN ANALYZE SELECT * FROM users WHERE id = 42;

И что он тебе выдаст, этот оракул:

Index Scan using users_pkey on users  (cost=0.15..8.17 rows=1 width=72) (actual time=0.021..0.022 rows=1 loops=1)
  Index Cond: (id = 42)
Planning Time: 0.078 ms
Execution Time: 0.043 ms

Главное в этой каше — смотреть на ключевые вещи:

  • cost: Циферки, показывающие, насколько операция «дорогая». Чем меньше — тем лучше, епта.
  • rows: Сколько строк, по мнению базы, вернётся. Если она думает, что вернётся 10, а на деле миллион — это повод задуматься, а не ебёт ли её.
  • actual time: А вот это уже святое — реальное время выполнения. Когда видишь там 1000 ms на одной строчке — понимаешь, где нужно копать.
  • Тип сканирования: Увидел Seq Scan (последовательное чтение всей таблицы) — готовься к боли. Увидел Index Scan или Index Only Scan — можно выдохнуть, работает как надо.

В Go ты просто через стандартный database/sql этот запрос выполняешь, как любой другой, и читаешь результат как текст. Никакой магии, просто бесценная инфа, чтобы не гадать на кофейной гуще, почему всё еле ползёт.