Оценивается ли короткое замыкание предложения SQL WHERE? - PullRequest
132 голосов
/ 25 апреля 2009

Например:

SELECT * 
FROM Table t 
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key) 

Если @ ключ равен NULL имеет значение true, @ ключ НЕ равен NULL И @key = t.Key оценивается?

Если нет, то почему бы и нет?

Если да, это гарантировано? Это часть ANSI SQL или это база данных?

Если база данных специфична, SqlServer? Oracle? MySQL?

Ссылка: Оценка короткого замыкания

Ответы [ 14 ]

66 голосов
/ 26 мая 2009

ANSI SQL Draft 2003 5WD-01-Framework-2003-09.pdf

6.3.3.3 Порядок оценки правил

[...]

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

57 голосов
/ 07 сентября 2012

Из вышесказанного короткое замыкание на самом деле не доступно.

Если вам это нужно, я предлагаю выписку по делу:

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

Expr1 всегда оценивается, но только один из Expr2 и Expr3 будет оцениваться в строке.

18 голосов
/ 25 апреля 2009

Я думаю, что это один из случаев, когда я написал бы его так, как если бы он не закорачивался по трем причинам.

  1. Поскольку для MSSQL это не решается, глядя на BOL в очевидном месте, поэтому для меня это делает его канонически двусмысленным.

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

  3. Я пишу достаточно часто для нескольких продуктов СУБД, и мне не нужно запоминать различия, если я могу легко их обойти.

12 голосов
/ 25 апреля 2009

Я не верю, что короткое замыкание в SQL Server (2005) гарантировано. SQL Server выполняет ваш запрос через свой алгоритм оптимизации, который учитывает множество вещей (индексы, статистика, размер таблицы, ресурсы и т. Д.), Чтобы разработать эффективный план выполнения. После этой оценки вы не можете точно сказать, что ваша логика короткого замыкания гарантирована.

Некоторое время назад я сам столкнулся с тем же вопросом, и мои исследования действительно не дали мне однозначного ответа. Вы можете написать небольшой запрос, чтобы дать вам ощущение того, что он работает, но можете ли вы быть уверены, что по мере увеличения нагрузки на базу данных таблицы будут увеличиваться, а в базе данных все будет оптимизировано и изменено, такой вывод будет держать. Я не мог и поэтому допустил ошибку из-за предосторожности и использовал условие CASE в WHERE для обеспечения короткого замыкания.

7 голосов
/ 26 апреля 2009

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

3 голосов
/ 29 апреля 2009

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

SELECT  [blah]
FROM    Emp
WHERE  ((@EmpID = -1) OR (@EmpID = EmpID))

Это дает мне возможность передать -1 или что-то еще для учета необязательной проверки атрибута. Иногда это подразумевает объединение нескольких таблиц или, предпочтительно, представления.

Очень удобно, не совсем уверен в дополнительной работе, которую он дает движку БД.

2 голосов
/ 14 августа 2012

Просто наткнулся на этот вопрос и уже нашел эту запись в блоге: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/

Сервер SQL может свободно оптимизировать запрос в любом удобном для него месте, поэтому в примере, приведенном в сообщении в блоге, нельзя полагаться на короткое замыкание.

Тем не менее, документ CASE, по-видимому, задокументирован для оценки в письменном порядке - проверьте комментарии к этому сообщению в блоге.

2 голосов
/ 26 апреля 2009

я не знаю о коротких замыканиях, но я бы написал это как выражение if-else

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

     SELECT * 
     FROM Table t 
     WHERE t.Key=@key

end

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

http://en.wikipedia.org/wiki/Sargable

2 голосов
/ 25 апреля 2009

Я думаю, что для SQL Server это зависит от версии, но мой опыт работы с SQL Server 2000 заключается в том, что он все еще оценивает @key = t.Key, даже если @key равен нулю. Другими словами, он не обеспечивает эффективного короткого замыкания при оценке предложения WHERE.

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

Этот тип гибкого запроса с различными критериями, вероятно, является одним из случаев, когда динамически создаваемый SQL действительно лучший путь. Если @key равен нулю, вы просто не включаете его в запрос вообще.

1 голос
/ 15 ноября 2016

Вот демонстрация, чтобы доказать, что MySQL выполняет короткое замыкание предложения WHERE :

http://rextester.com/GVE4880

Запускаются следующие запросы:

SELECT myint FROM mytable WHERE myint >= 3 OR myslowfunction('query #1', myint) = 1;
SELECT myint FROM mytable WHERE myslowfunction('query #2', myint) = 1 OR myint >= 3;

Единственная разница между ними - это порядок операндов в условии ИЛИ.

myslowfunction намеренно спит на секунду и имеет побочный эффект добавления записи в таблицу журнала при каждом запуске. Вот результаты того, что регистрируется при выполнении вышеупомянутых двух запросов:

myslowfunction called for query #1 with value 1
myslowfunction called for query #1 with value 2
myslowfunction called for query #2 with value 1
myslowfunction called for query #2 with value 2
myslowfunction called for query #2 with value 3
myslowfunction called for query #2 with value 4

Выше показано, что медленная функция выполняется чаще, когда она появляется слева от условия ИЛИ, когда другой операнд не всегда имеет значение true (из-за короткого замыкания).

...