Мы пишем SELECT первым, хотя движок добирается до него далеко не сразу. Понимание этого порядка часто проверяют на собеседованиях по SQL, аналитике и Data Engineering.
Упрощённый логический порядок выглядит так:
FROM → JOIN → WHERE → GROUP BY → HAVING → оконные функции → SELECT → DISTINCT → ORDER BY → LIMIT
⬇️Какие отсюда следствия:
• WHERE фильтрует исходные строки до группировки;
• HAVING работает уже с результатами группировки;
• оконные функции считаются после WHERE, GROUP BY и HAVING, поэтому обратиться к результату ROW_NUMBER() в WHERE того же запроса нельзя (важно);
• ORDER BY видит алиасы из SELECT, а WHERE обычно ещё не видит.
Например, если нужно оставить только первую строку внутри каждой группы, придётся использовать подзапрос, CTE или QUALIFY, если СУБД его поддерживает.
Но логический порядок ещё не означает, что база физически выполнит операции именно так.
⬆️Оптимизатор может:
• протолкнуть фильтр ближе к чтению данных;
• не читать лишние столбцы и партиции;
• поменять порядок JOIN;
• выбрать Hash Join, Merge Join или Broadcast Join;
• добавить сортировку, Exchange или Shuffle.
По плану выполнения можно заметить полное чтение таблицы вместо нужных партиций, лишний Shuffle, перекос данных, неудачную стратегию JOIN или большую разницу между ожидаемым и фактическим количеством строк.
Поэтому к запросу стоит задавать не только вопрос «правильный ли получился результат?», но и «что движку пришлось сделать, чтобы его получить?».
В PostgreSQL для этого есть EXPLAIN ANALYZE, в Spark — explain() и Spark UI.
Сохраняй и ставь 🔥, если было полезно.
#материалы
