Можно ли применять скалярные функции перед фильтрацией при выполнении оператора SQL? - PullRequest
5 голосов
/ 09 марта 2011

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

Сегодня я отлаживал некоторый кодот продавца, и это предположение было оспорено.Единственная причина, по которой я могу думать об этом коде, заключается в том, что функция Substring () вызывается для данных, которые должны были быть отфильтрованы предложением WHERE.Но, похоже, что вызов подстроки применяется до того, как произойдет фильтрация, запрос не выполнен.Вот пример того, что я имею в виду.Допустим, у нас есть две таблицы, каждая из которых имеет 2 столбца и имеет 2 строки и 1 строку соответственно.Первый столбец в каждом является просто идентификатором.NAME - это просто строка, а NAME_LENGTH сообщает нам, сколько символов в имени имеет одинаковый идентификатор.Обратите внимание, что только имена с более чем одним символом имеют соответствующую строку в таблице LONG_NAMES.

NAMES: ID, NAME
    1, "Peter"
    2, "X"
LONG_NAMES: ID, NAME_LENGTH
    1, 5

Если я хочу, чтобы запрос печатал каждое имя с обрезанными последними 3 буквами, я мог бы сначала попробовать что-то вродеэто (предполагая синтаксис SQL Server на данный момент):

SELECT substring(NAME,1,len(NAME)-3)
    FROM NAMES;

Я скоро обнаружу, что это даст мне ошибку, потому что, когда он достигает "X", он попытается использовать отрицательное число для в подстрокепозвоните, и это не удастся.Мой поставщик решил решить эту проблему, отфильтровав строки, строки которых были слишком короткими для выполнения запроса len - 3.Он сделал это, присоединившись к другой таблице:

SELECT substring(NAMES.NAME,1,len(NAMES.NAME)-3) 
    FROM NAMES 
        INNER JOIN LONG_NAMES 
            ON NAMES.ID = LONG_NAMES.ID;

На первый взгляд этот запрос выглядит так, как будто он может работать.Условие соединения удалит все строки, поля NAME которых достаточно короткие для вызова подстроки.

Однако из того, что я могу наблюдать, SQL Server иногда пытается вычислить выражение подстроки для всего в таблицеи затем примените объединение для фильтрации строк.Это должно произойти таким образом?Есть ли документированный порядок операций, где я могу узнать, когда произойдут определенные вещи?Это специфично для конкретного движка базы данных или части стандарта SQL?Если бы я решил включить в свою таблицу NAMES какой-нибудь предикат для фильтрации коротких имен (например, len (NAME)> 3), может ли SQL Server также применить это после попытки применить подстроку?Если так, то кажется, что единственный безопасный способ сделать подстроку - заключить ее в конструкцию «случай, когда» в select?

Ответы [ 3 ]

2 голосов
/ 09 марта 2011

Мартин дал эту ссылку, которая в значительной степени объясняет, что происходит - у оптимизатора запросов есть свобода действий, чтобы изменить порядок вещей так, как ему нравится.Я включил это в качестве ответа, чтобы я мог принять что-то.Мартин, если ты создашь ответ со своей ссылкой, я с радостью приму его вместо этого.

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

TSQL делится на ноль, несмотря на отсутствие столбцов, содержащих 0

РЕДАКТИРОВАТЬ: По мере поступления новых ответов я снова запутался.Пока не ясно, когда именно оптимизатору разрешено оценивать вещи в предложении select.Я думаю, мне придется самому найти стандарт SQL и посмотреть, смогу ли я понять его.

1 голос
/ 09 марта 2011

Джо Селко, который помог написать ранние стандарты SQL, несколько раз публиковал нечто похожее на это в различных новостных группах USENET. (Я пропускаю пункты, которые не относятся к вашему утверждению SELECT.) Он обычно говорил что-то вроде: «Вот как операторы должны действовать так, как они работают». Другими словами, реализации SQL должны вести себя точно так же, как если бы они выполняли эти шаги, фактически не требуя выполнения каждого из этих шагов.

  1. Создайте рабочий стол из всех конструкторы таблиц в ОТ пункт.
  2. Снимите с рабочего стола тех строки, которые не удовлетворяют ГДЕ пункт.
  3. Построить выражения в Предложение SELECT для рабочего стола.

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

В недавней публикации Джо расширяет шаги, чтобы включить CTE .

СиДжей Дэйт и Хью Дарвен по существу говорят то же самое в главе 11 («Табличные выражения») своей книги Руководство по стандарту SQL . Они также отмечают, что эта глава соответствует разделу «Спецификация запроса» (разделы?) В стандартах SQL.

0 голосов
/ 09 марта 2011

Вы думаете о чем-то, что называется планом выполнения запроса.Он основан на правилах оптимизации запросов, индексах, временных буферах и статистике времени выполнения.Если вы используете SQL Managment Studio, у вас есть панель инструментов над редактором запросов, где вы можете посмотреть примерный план выполнения, он показывает, как ваш запрос изменится, чтобы набрать некоторую скорость.Так что, если вы просто использовали вашу таблицу имен и она находится в буфере, движок может сначала попытаться запросить ваши данные, а затем объединить их с другой таблицей.

...