Страницы

21 июля 2013 г.

SQL. Команда SELECT. Последовательность выполнения.


Доброго времени суток.
       Я сравнительно давно пользуюсь SQL для доступа и обработки данных, и мне всегда было интересно как SQL обрабатывается интерпритатором. Т.е. мне было интересно что происходит "под капотом". Возьмем оператор SELECT. Все кто хоть что-то читал про работу серверов БД с поддержкой SQL знают, что запросы не просто интерпретируются и исполняются,а еще и генерируются планы выполнения, которые проходят ряд проверок и оптимизаций перед тем как результат возвращается запустившему запрос процессу. Это знают все, но не все знают что это такое и как оно работает в действительности. Про планы выполнения и оптимизацию я постараюсь вспомнить чуть позже, в другой статье. Здесь речь пойдет о последовательности выполнения оператора SELECT.

Итак, для примера возьмем запрос к таблицам моей рабочей БД.

SELECT name, COUNT(*) as cnt
FROM dbo.orderitem
WHERE parentid IS NULL
GROUP BY name 
HAVING COUNT(*) > 1
ORDER BY name

       Этот запрос возвращает наименования заказов количество позиций в которых превышают единицу.
       После запуска запроса SQL иинтерпритатор обрабатывает представленный выше запрос не той последовательности в которой он написан, а в несколько иной:
  1. FROM dbo.orderitem
  2. WHERE parentid is null
  3. GROUP BY name
  4. HAVING COUNT(*) > 1
  5. SELECT name, COUNT(*) as cnt
  6. ORDER BY name
       Другими словами, сначала предложение FROM указывает на таблицу из которой мы будем выбирать данные, WHERE - фильтрует данные, оставляя только те записи которые удовлетворяют условию. Далее запускается механизм группировки строк - GROUP BY, после группировки применяется предикат для групп строк(!) - HAVING. (HAVING относится именно к отгруппированным строкам, его применение без GROUP BY невозможно). Уже после этого выполняется часть запроса SELECT, которая определяет перечень атрибутов (столбцов) для отображения, а так же позволяет применять вычисляемые выражения (в нашем случае COUNT(*)). После того как перечень выводимых атрибутов определен применяется сортировка (ORDER BY).
Именно в такой последовательности исполняются однотабличные запросы SELECT. Такая последовательность объясняет появления ошибки в случаях, если мы, например, в предложении WHERE захотим использовать псевдоним поля указанный в блоке SELECT.

SELECT name, COUNT(*) as cnt
FROM dbo.orderitem
WHERE parentid IS NULL
AND cnt <> 0     --ОШИБКА! Поля cnt в таблице не существует
GROUP BY name 
HAVING COUNT(*) > 1
ORDER BY name

Ошибка сгенерится потому, что часть WHERE исполняется ранее чем SELECT, и на момент выполнения блок WHERE еще ничего не знает о псевдонимах предоставляемых блоком SELECT.

Комментариев нет:

Отправить комментарий