Порядок выполнения SQL-запроса на собеседовании
Почему порядок выполнения спрашивают на каждом собеседовании
SQL пишется в одном порядке, а выполняется в другом. Мы пишем SELECT первым, но база данных обрабатывает его почти последним. Непонимание этого приводит к ошибкам, которые сложно отловить — запрос работает, но возвращает неправильный результат. Поэтому вопрос о порядке выполнения стал стандартом на собеседованиях аналитиков.
Интервьюер может спросить прямо: «В каком порядке выполняется SQL-запрос?» Но чаще вопрос замаскирован: «Почему нельзя использовать алиас из SELECT в WHERE?» или «Почему HAVING фильтрует после GROUP BY, а WHERE — до?»
Понимание порядка выполнения SQL — это не теория ради теории. Это ключ к правильному написанию запросов и объяснению, почему конкретный запрос работает именно так.
Логический порядок выполнения
Вот порядок, в котором база данных логически обрабатывает запрос:
1. FROM и JOIN — определяется источник данных. Таблицы соединяются, применяются условия ON. Результат — промежуточная таблица со всеми строками.
2. WHERE — фильтруются строки из промежуточной таблицы. Строки, не удовлетворяющие условию, отбрасываются. На этом этапе агрегатные функции недоступны.
3. GROUP BY — оставшиеся строки группируются по указанным колонкам. Каждая группа схлопывается в одну строку.
4. HAVING — фильтруются группы. В отличие от WHERE, здесь можно использовать агрегатные функции: HAVING COUNT(*) > 5.
5. SELECT — вычисляются выражения и создаются алиасы. Именно поэтому алиасы из SELECT нельзя использовать в WHERE — на момент фильтрации они ещё не существуют.
6. DISTINCT — удаляются дубликаты, если указано.
7. ORDER BY — результат сортируется. Здесь алиасы из SELECT уже доступны.
8. LIMIT / OFFSET — обрезается результат до нужного количества строк.
Ошибки из-за непонимания порядка
Алиас в WHERE. Запрос SELECT price * quantity AS total FROM orders WHERE total > 1000 не сработает в большинстве СУБД. WHERE выполняется до SELECT, алиас total ещё не вычислен. Правильно: повторить выражение в WHERE или использовать подзапрос.
Агрегат в WHERE. Запрос SELECT department, AVG(salary) FROM employees WHERE AVG(salary) > 50000 GROUP BY department вернёт ошибку. WHERE работает до GROUP BY, агрегатные функции ещё не рассчитаны. Правильно: использовать HAVING.
Алиас в GROUP BY. В PostgreSQL и MySQL алиас из SELECT можно использовать в GROUP BY — это расширение стандарта. В других СУБД это может не работать. На собеседовании стоит упомянуть, что поведение зависит от СУБД.
ORDER BY с номером колонки. ORDER BY 1 сортирует по первой колонке в SELECT. Это работает, потому что ORDER BY выполняется после SELECT. Но на практике такой синтаксис хрупкий — изменение порядка колонок в SELECT сломает сортировку.
Практическое значение для аналитика
Знание порядка выполнения помогает при оптимизации. WHERE фильтрует до GROUP BY — значит, чем раньше вы отсеете ненужные строки, тем меньше данных придётся группировать. Это принцип «фильтруй рано»: условия, которые можно перенести из HAVING в WHERE, почти всегда ускоряют запрос.
Ещё один пример: оконные функции вычисляются на этапе SELECT, после GROUP BY и HAVING. Это значит, что оконная функция работает уже с агрегированными данными, а не с исходными строками.
Совет для собеседования: если вас просят объяснить результат сложного запроса, проговаривайте порядок выполнения вслух. Это показывает системное мышление и помогает не запутаться.
Как запомнить порядок
Мнемоника: FROM — WHERE — GROUP BY — HAVING — SELECT — ORDER BY — LIMIT. Некоторые запоминают по первым буквам: F-W-G-H-S-O-L. Другие используют аналогию с конвейером: сначала берём сырьё (FROM), фильтруем (WHERE), группируем (GROUP BY), отбираем группы (HAVING), формируем результат (SELECT), сортируем (ORDER BY), обрезаем (LIMIT).
На практике достаточно решить десяток задач, осознанно проговаривая порядок — после этого он запоминается автоматически. Тренироваться можно в Карьернике: в разделе SQL есть задачи, где понимание порядка критично для правильного ответа.
FAQ
Почему алиас из SELECT работает в ORDER BY, но не в WHERE?
Потому что ORDER BY выполняется после SELECT, а WHERE — до. На момент фильтрации в WHERE алиас ещё не существует. ORDER BY видит уже вычисленные колонки, включая алиасы. Это одно из самых практических следствий порядка выполнения.
Отличается ли порядок выполнения в разных СУБД?
Логический порядок одинаков во всех СУБД — это часть стандарта SQL. Но физический порядок (как оптимизатор реально выполняет запрос) может отличаться. Оптимизатор вправе менять порядок операций, если результат будет тем же. На собеседовании говорите о логическом порядке.
Где в этом порядке находятся подзапросы и CTE?
CTE (WITH) вычисляются до основного запроса. Подзапросы в FROM обрабатываются на этапе FROM, подзапросы в WHERE — на этапе WHERE. Каждый подзапрос имеет свой внутренний порядок выполнения. Подробнее — в статье про подзапросы и CTE.