Вычисляется ли короткое замыкание предложения SQL WHERE?

Оцениваются ли логические выражения в предложениях SQL WHERE ?

Например:

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

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

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

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

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

Ответ 1

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

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

[...]

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

Ответ 2

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

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

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

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

Ответ 3

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

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

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

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

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

Ответ 7

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

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

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

Ответ 8

Я не знаю о коротком обращении, но я бы написал его как оператор if-else

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

     SELECT * 
     FROM Table t 
     WHERE [email protected]

end

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

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

Ответ 9

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

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

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

Ответ 10

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

Двоичные логические операторы являются ком мутативными, что означает:

a AND b == b AND a
a OR  b == b OR  a
a XOR b == b XOR a

поэтому нет гарантии по порядку оценки. Порядок оценки будет определяться оптимизатором запросов.

В языках с объектами могут быть ситуации, когда вы можете писать логические выражения, которые могут быть оценены только с оценкой короткого замыкания. Ваша типовая конструкция кода часто используется на таких языках (С#, Delphi, VB). Например:

if(someString == null | someString.Length == 0 )
  printf("no text in someString");

Этот пример С# вызовет исключение, если someString == null, потому что он будет полностью оценен. При оценке короткого замыкания он будет работать каждый раз.

SQL работает только с скалярными переменными (без объектов), которые не могут быть неинициализированы, поэтому невозможно написать логическое выражение, которое невозможно оценить. Если у вас есть значение NULL, любое сравнение вернет false.

Это означает, что в SQL вы не можете писать выражение, которое по-разному оценивается в зависимости от использования короткого замыкания или полной оценки.

Если реализация SQL использует оценку короткого замыкания, можно только надеяться ускорить выполнение запроса.

Ответ 11

Ниже быстрого и грязного теста на SQL Server 2008 R2:

SELECT *
FROM table
WHERE 1=0
AND (function call to complex operation)

Это немедленно возвращается без записей. Вид поведения короткого замыкания присутствовал.

Тогда попробовал это:

SELECT *
FROM table
WHERE (a field from table) < 0
AND (function call to complex operation)

зная, что никакая запись не удовлетворяет этому условию:

(a field from table) < 0

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

Надеюсь, это поможет парням.

Ответ 12

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

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;

Единственное различие между ними - порядок операндов в условии OR.

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

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

Ответ 13

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

SET @ADate = NULL

IF (@ADate IS NOT NULL)
BEGIN
    INSERT INTO #ABla VALUES (1)
        (SELECT bla from a huge view)
END

Было бы неплохо иметь гарантированный способ!

Ответ 14

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

Поддерживающий пример:

SELECT 'TEST'
WHERE 1 = 'A'

SELECT 'TEST'
WHERE 1 = 1 OR 1 = 'A'

Здесь первый пример приведет к ошибке "Ошибка конверсии при преобразовании значения varchar" A "в тип данных int. '

В то время как вторая выполняется легко, так как условие 1 = 1 оценивается как ИСТИНА, и, следовательно, второе условие не работает вообще.

Далее

SELECT 'TEST'
WHERE 1 = 0 OR 1 = 'A'

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

ПРИМЕЧАНИЕ. Я РАЗРУШАЮЩИЙ УСЛОВИЕ ТОЛЬКО ДЛЯ РЕАЛИЗИРОВАНИЯ ПОГОДЫ СОСТОЯНИЕ ВЫПОЛНИТСЯ ИЛИ КРАТКОСРОЧНО ЕСЛИ РЕЗУЛЬТАТЫ QUERY В ОШИБКЕ СОХРАНЯЮТ СОСТОЯНИЕ, ВЫПОЛНЕННОЕ, КОРОТКО-ЦИРКУЛИРОВАННОЕ ИНОЕ.

ПРОСТОЕ ОБЪЯСНЕНИЕ

Рассмотрим,

WHERE 1 = 1 OR 2 = 2

поскольку первое условие оценивается как TRUE, его бессмысленно оценивать второе условие, потому что его оценка в любом значении не повлияет на результат вообще, поэтому его хорошая возможность для Sql Server сохранить время выполнения запроса, пропустив ненужную проверку состояния или оценку.

в случае "ИЛИ" , если первое условие оценивается как ИСТИНА, вся цепочка, связанная "ИЛИ" , считается оцененной как true, не оценивая других.

condition1 OR condition2 OR ..... OR conditionN

если условие 1 оценивается как истинное, оставим все условия до тех пор, пока условие N не будет пропущено. В обобщенных словах при определении первого TRUE все остальные условия, связанные с OR, будут пропущены.

Рассмотрим второе условие

WHERE 1 = 0 AND 1 = 1

поскольку первое условие получает evalutated до FALSE его бессмысленно оценивать второе условие, потому что его оценка в любом значении не повлияет на результат вообще, поэтому снова его хорошая возможность для Sql Server сохранить время выполнения запроса, пропустив ненужную проверку состояния или оценку.

в случае "И" , если первое условие оценивается как ЛОЖЬ, вся цепочка, связанная с "И" , считается оцененной к FALSE без оценки других.

condition1 AND condition2 AND ..... conditionN

если условие 1 оценивается как FALSE, остальные условия сохраняются до тех пор, пока условиеN не будет пропущено. В обобщенных словах при определении первого FALSE все остальные условия, связанные с И, будут пропущены.

ПОЭТОМУ, ПРОСТРАНСТВУЮЩИЙ ПРОГРАММА ДОЛЖНА ВСЕГДА ПРОГРАММА СЕТИ УСЛОВИЙ В ТАКОЙ ПУТЬ, ЧТО, МЕНЕЕ РАСПРОСТРАНЕННОЕ ИЛИ НАИБОЛЕЕ ЛИКВИДАЦИОННОЕ СОСТОЯНИЕ ПОЛУЧАЕТ ОЦЕНКУ ПЕРВОГО, ИЛИ СОХРАНЯЙТЕ СОСТОЯНИЕ В ТАКОЙ ПУТЕМ, КОТОРЫЙ МОЖЕТ ПРИНЯТЬ МАКСИМАЛЬНОЕ ПРЕИМУЩЕСТВО КОРОТКОГО ЦЕПЬ