Как различаются порядки выполнения SQL в разных базах данных

Особенности выполнения SQL-запросов в различных базах данных

Почему нельзя группировать по порядковым позициям в SQL Server, но можно в других базах данных

Порядок выполнения Transact-SQL и MySQL (изображение автора)

После регулярной работы с открытыми базами данных, такими как MySQL и PostgreSQL, недавно мне выпала возможность поработать над проектом на SQL Server и я обнаружил тонкую, но важную разницу в архитектуре SQL. Я заметил, что в SQL Server я не могу группировать по порядковым позициям (GROUP BY 1, 2, 3…), что я часто делал в других базах данных, особенно для быстрого тестирования.

Это открытие побудило меня исследовать несколько нюансов обоих систем управления базами данных, в частности, порядок выполнения SQL, который будет фокусом этой статьи.

Почему это важно? При работе с системами управления базами данных понимание тонких различий может существенно повлиять на ваш рабочий процесс и увеличить производительность. Это может сэкономить значительное количество времени при устранении ошибок. Кроме того, понимая порядок выполнения SQL в различных базах данных, вы можете создавать более оптимальные SQL запросы в зависимости от системы, с которой вы работаете.

В этой статье мы рассмотрим один из основных случаев, когда возникает такое поведение — GROUP BY — и исследуем причины. Однако, данное понимание можно применить и к таким командам SQL, как HAVING, WHERE или любому другому оператору.

Начнем

Давайте рассмотрим этот пример в запросе ниже. В SQL Server это не будет работать, хотя в MySQL работает:

SELECT    DATEPART(year, day) AS order_date,    SUM(cost) as costFROM cleanGROUP BY 1;

Если вы запустите это, вы, вероятно, получите ошибку, подобную следующей:

Each GROUP BY expression must contain at least one column that is not an outer reference.

Однако, этот исправленный запрос работает после замены порядковой ссылки в GROUP BY явным выражением. Вы также заметите, что вы можете использовать порядковые позиции в ORDER BY, что я нашел странным:

SELECT    datepart(year, day),    sum(cost) as costfrom cleanGROUP BY datepart(year, day)ORDER BY 1;

В SQL Server я быстро узнал, что мне нужно использовать явные имена столбцов или выражения в операторе GROUP BY. Это считается хорошей практикой, так как облегчает понимание кода. Однако, меня интересовало, почему это поведение различается в каждой базе данных. Кроме того, мне было интересно то, что в SQL Server можно использовать порядковые позиции в операторе ORDER BY, что еще больше пробудило мое любопытство.

Исследование порядка выполнения оператора SELECT

Для выяснения этого, давайте рассмотрим порядок выполнения/обработки оператора SELECT в SQL Server по сравнению с другими базами данных. Важно отметить, что в SQL базах данных каждая часть запроса выполняется последовательно и этот порядок отличается от его написания.

В SQL Server, например, мы можем видеть на изображении ниже и из документации Microsoft, что команда FROM является первой, которая выполняется. Кроме того, команда SELECT выполняется после команды GROUP BY. Вот почему мы не смогли ссылаться на позицию столбца или даже его псевдоним в операторе GROUP BY в нашем первом примере!

Однако мы свободны ссылаться на порядковую позицию и/или псевдоним в операторе ORDER BY, так как это выполняется после оператора SELECT. Оператор SELECT сообщает базе данных, какие столбцы будут возвращены, и, следовательно, известно их позиционирование на этом этапе. Круто, не правда ли?

Порядок выполнения SQL Server

Порядок обработки оператора SELECT в SQL Server (изображение автора)

MySQL

Однако в MySQL я обнаружил, что трудно найти четкую документацию о порядке выполнения SQL-запроса. Порядок выполнения, кажется, зависит от содержимого запроса и того, как оптимизатор запроса определяет наилучший путь.

Но из того, что мы можем видеть здесь, в документации MySQL, нам показывается, как порядок выполнения может быть, и что клауза SELECT оценивается перед клаузой GROUP BY:

Для клаузы GROUP BY или HAVING он ищет в клаузе FROM перед поиском значений в select_expr. (При использовании GROUP BY и HAVING это отличается от предшествующего поведения MySQL 5.0, которое использовало те же правила, что и для ORDER BY.)

GoogleSQL

Если мы также посмотрим на документацию GoogleSQL (ранее Standard SQL) здесь, которая является синтаксисом, используемым в Google BigQuery, вы увидите аналогичное отклонение от способа выполнения запросов в SQL Server:

Клаузы GROUP BY и ORDER BY также могут относиться к третьей группе: целочисленным литералам, которые относятся к элементам в списке SELECT. Целое число 1 относится к первому элементу в списке SELECT, 2 относится ко второму элементу и т.д.

Как видно, такое поведение не поддерживается в SQL Server. В документации Google также упоминается, что клаузы GROUP BY, ORDER BY и HAVING могут ссылаться на псевдонимы из списка SELECT.

Поэтому мы можем сделать вывод с высокой вероятностью, что порядок выполнения для этих других баз данных следует похожему пути, показанному на изображении ниже:

Предполагаемый порядок выполнения MySQL, PostgreSQL & BigQuery

Порядок выполнения оператора SELECT в MySQL (Изображение автора)

Заключение

Это был короткий пост, в котором мы рассмотрели, как порядок выполнения в MySQL, GoogleSQL и синтаксисах SQL других баз данных отличается от SQL Server, на основе наблюдаемого поведения и документации. SQL Server акцентирует явность в клаузе GROUP BY для ясности кода, в то время как порядок выполнения MySQL безусловно оценивает клаузу SELECT перед клаузой GROUP BY, позволяя нам ссылаться на порядковые позиции в ней.

Не стесняйтесь делиться своими мыслями по этому вопросу и жду вас в следующем материале.

Вы можете стать участником VoAGI, чтобы поддержать меня и наслаждаться большим количеством подобных историй.

Ссылки