Что такое EXPLAIN в SQL?

Ответ

EXPLAIN — это SQL-команда (или её аналог), которая показывает план выполнения запроса, не выполняя его фактически. Это основной инструмент для анализа и оптимизации производительности запросов, позволяющий понять, как СУБД будет его обрабатывать: какие индексы она выберет, в каком порядке соединит таблицы и какие временные структуры создаст.

Типичный вывод EXPLAIN для C++ разработчика: Разработчик на C++, работающий с базами данных (например, через ODBC, libpqxx для PostgreSQL или MySQL Connector/C++), использует EXPLAIN для отладки «тяжёлых» запросов. Вывод — это набор строк, описывающих шаги (узлы) плана. Ключевые столбцы:

  • type / access_type: Метод доступа к таблице (ALL — полное сканирование, index — сканирование индекса, range — диапазон по индексу, const — поиск по уникальному ключу). ALL часто указывает на потенциальную проблему.
  • key: Индекс, который будет использован.
  • rows: Оценочное количество строк, которые должен обработать этот шаг.
  • Extra: Дополнительная информация (например, Using where, Using temporary, Using filesort). Using filesort или Using temporary могут сигнализировать о необходимости оптимизации.

Пример анализа запроса:

-- Допустим, есть таблица 'orders' с индексами на (customer_id) и (status, created_at)
EXPLAIN 
SELECT * FROM orders 
WHERE customer_id = 100 AND status = 'shipped' 
ORDER BY created_at DESC;
Возможный вывод и его интерпретация: id select_type table type possible_keys key rows Extra
1 SIMPLE orders ref customer_id,status customer_id 15 Using where; Using filesort

Анализ: Запрос использует индекс по customer_id (это хорошо), но для фильтрации по status и сортировки по created_at приходится делать дополнительную работу (Using where; Using filesort). Это может быть медленно, если строк с customer_id=100 много. Решение из C++ перспективы: перед внедрением запроса в код можно предложить добавить составной индекс (customer_id, status, created_at), который покроет все условия и избавит от сортировки вручную.

EXPLAIN ANALYZE (PostgreSQL, MySQL 8.0+): Более мощная команда, которая фактически выполняет запрос и возвращает реальные метрики (время, количество возвращённых строк), что позволяет точно оценить стоимость каждого узла плана и найти узкие места.

Ответ 18+ 🔞

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

Что видит C++ разработчик, когда смотрит в EXPLAIN: Представь, ты пишешь на плюсах и через какую-нибудь либу вроде libpqxx или ODBC дергаешь базу. Запрос тормозит так, что терпения ноль ебать. Ты не гадаешь на кофейной гуще, а вставляешь перед ним EXPLAIN. На выходе получаешь этакую табличку, где каждая строка — это шаг в плане выполнения. Главное, на что смотреть:

  • type (или access_type): Это метод доступа к таблице. Если видишь ALL — это полный пиздец, сканирование всей таблицы, как будто ты ищешь иголку в стоге сена, перебирая каждую соломинку. index — уже лучше, сканирует индекс. range — совсем хорошо, диапазон по индексу. const — идеально, нашёл по уникальному ключу сразу.
  • key: Собственно, какой индекс будет использоваться. Если тут NULL, а в соседнем столбце possible_keys не пустой — это повод задуматься, почему оптимизатор — такой пидарас шерстяной — проигнорировал твои красивые индексы.
  • rows: Оценочное количество строк, которые этот шаг должен перелопатить. Если цифра овердохуища, а на следующем шаге она резко падает — значит, фильтрация работает поздно, и это кандидат на оптимизацию.
  • Extra: А вот тут вся соль. Если видишь Using temporary — это значит, что для обработки запроса создаётся временная таблица (часто на диске, что медленно как хуй с горы). Using filesort — сортировка делается отдельным проходом, а не через индекс. Это как раз те места, где запрос начинает бздеть и тормозить.

Разберём на живом примере, чтобы не быть голословным: Допустим, есть таблица заказов orders. Индексы есть на customer_id и на пару (status, created_at). А запрос у нас такой:

EXPLAIN
SELECT * FROM orders
WHERE customer_id = 100 AND status = 'shipped'
ORDER BY created_at DESC;

Что может показать EXPLAIN (условный вывод):

id select_type table type possible_keys key rows Extra
1 SIMPLE orders ref customer_id,status customer_id 15 Using where; Using filesort

Анализ и перевод с языка БД на человеческий: Смотри, оптимизатор выбрал индекс по customer_id (столбец key). Вроде неплохо, нашел все заказы клиента 100. Но дальше в Extra горят два красных флажка: Using where; Using filesort.

  • Using where — это он говорит: «Я по индексу нашёл строки по customer_id, но теперь мне придётся каждую из этих 15 строк (столбец rows) вручную проверить на условие status = 'shipped', потому что индекс по customer_id про статус нихуя не знает».
  • Using filesort — а это уже совсем весёлое: «А теперь, чувак, я эти отфильтрованные результаты ещё и отсортирую по created_at вручную, потому что опять же, выбранный индекс мне не помогает с сортировкой».

Что делать? С точки зрения C++ подхода: Не надо сразу лезть в код и пытаться как-то хитро переписать запрос. Чаще всего проблема решается на стороне базы. Глядя на этот план, сразу видно — нужен составной индекс, который покроет все три поля: (customer_id, status, created_at). Тогда база сможет:

  1. Мгновенно найти все заказы клиента 100 (customer_id).
  2. Сразу отфильтровать только те, у которых статус 'shipped' (status — следующий столбец в индексе).
  3. И сразу выдать их уже в отсортированном по created_at виде, потому что индекс хранит данные в порядке своих столбцов.

Запрос после создания такого индекса может начать летать, и тебе не придётся в коде городить костыли и ручные сортировки.

А есть EXPLAIN ANALYZE (PostgreSQL, MySQL 8.0+)? А вот это, блядь, настоящий инструмент для мазохистов и перфекционистов! Эта команда не просто строит план, а реально выполняет запрос и потом показывает, сколько времени на самом деле ушло на каждый шаг, сколько строк прошло и т.д. Это как EXPLAIN, но с настоящими, а не оценочными таймингами. Если EXPLAIN — это план сметы от прораба, то EXPLAIN ANALYZE — это отчёт бухгалтера после стройки, где видно, на чём реально сэкономили, а где, блядь, всё просрали и ушли в перерасход. Используй, когда нужно докопаться до самой сути тормозов.