2009-04-25 5 views
115

Например:Является ли вычисление условий предложения WHERE SQL WHERE?

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

Если @key IS NULL истинно, является @key НЕ NULL И @key = t.Key оценивали?

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

Если да, то это гарантировано? Является ли он частью ANSI SQL или является ли он специфичным для базы данных?

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

Ссылка: Short Circuit Evaluation

+0

Не является ли пункт @key НЕ НУЛЛ избыточным? Предложение @key IS NULL на LHS позаботится об этом нет? – spender

+9

@splender - зависит от ответа на вопрос –

+0

@Greg: Я согласен с spender. Я не вижу недостатка или наличия короткого замыкания, что имеет значение. Если @key IS NULL, то @key = t.Key всегда будет возвращать false, как NULL! = NULL (именно поэтому мы используем IS NULL, в конце концов). –

ответ

59

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

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

[...]

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

+1

Реализация зависит? Отлично. Полезно знать. По крайней мере, 'CASE' закорочен. – dakab

+1

Разве это не означает, что оценки выражений не определены? "(0 = 0 ИЛИ NULL)", всегда равно NULL, если все члены оцениваются, но всегда истинны, если оцениваются слева направо и закорочены. – user48956

+0

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

2

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

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

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

12

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

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

18

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

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

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

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

+4

Отличное предложение. Это не отвечает на вопрос, но это большая прагматическая точка зрения. поэтому +1 –

1

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

Бинарные логические операторы comutative, что означает:

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

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

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

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

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

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

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

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

+1

Да, булевы операторы являются коммутативными. Я не думаю, что объекты (или нет) имеют к этому какое-то отношение. –

2

я не знаю, о коротком circuting, но я бы написать это как если-иначе заявления

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

+1

Может ли кто-нибудь подтвердить это переменными справа? По какой-то причине я с трудом верю в это. –

+0

http://searchoracle.techtarget.com/expert/KnowledgebaseAnswer/0,289625,sid41_gci1267806,00.html# еще не можете найти сейчас – DForck42

+0

Как я понимаю, статья. Речь идет о функциях по именам столбцов, которые не могут быть отклонены. Который я понимаю. Однако я не думаю (A = @a) или (@a = A). –

6

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

+6

Это важно для скорости выполнения! –

+0

Просто потому, что именно так работает в данный момент, это не значит, что его нельзя изменить. Мы должны отделить модель/семантику от реализации. Планы выполнения внедряются внутри страны для оптимизации выполнения запросов ... и семантика коротких замыканий не только противоречат декларативному характеру SQL, но и могут ограничивать такие оптимизации.Однако, если семантика оценки короткого замыкания должна была поддерживаться СУБД, реализация планов выполнения изменилась бы для поддержки такой семантики. –

3

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

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

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

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

+0

Да, это та же идея ... –

0

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

SET @ADate = NULL 

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

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

1

Ниже быстрый и грязный тест на 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 

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

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

+0

Я предполагаю, что первый запрос был «закорочен» во время компиляции, прежде чем выполнение плана действительно началось. –

3

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

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

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

52

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

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

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult 

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

+2

Это зависит от реализации РСУБД. По крайней мере для SQL Server существует, по крайней мере, одно исключение, которое документировано, чтобы не показывать это поведение (т. Е. Короткое замыкание); cf [CASE (Transact-SQL) - Примечания] (https://msdn.microsoft.com/en-us/library/ms181765.aspx#Anchor_3). Я процитировал это дело в [этом ответе] (http://stackoverflow.com/a/35848730/243373). Я задал вопрос * Sql - Явный порядок условий WHERE? *. –

+0

Case _expression_, а не оператор. – jarlh

-3

Это, но очевидно, что сервер 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' 

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

ПРИМЕЧАНИЕ: Я НАПИСАЛ ошибочные УСЛОВИЯ JUST ПРОВЕСТИ ПОГОДУ УСЛОВИЕ Выполнено ИЛИ короткозамкнутый ЕСЛИ РЕЗУЛЬТАТЫ ЗАПРОСА В ОШИБКАХ означают состояние казнено, короткозамкнутая ИНАЧЕ.

SIMPLE ОБЪЯСНЕНИЕ

Рассмотрим,

WHERE 1 = 1 OR 2 = 2 

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

в случае «ИЛИ», если первое условие оценивается в ИСТИНА всю цепочку, связанную с «ИЛИ» бы рассматривать как оценивали с истинным без оценки других.

condition1 OR condition2 OR ..... OR conditionN 

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

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

WHERE 1 = 0 AND 1 = 1 

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

в случае «И», если первое условие вычисляется в FALSE всю цепочку, связанную с «И» бы рассматривать как оценивали ЛОЖЬ без оценки других.

condition1 AND condition2 AND ..... conditionN 

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

НИХ, мудрая программист должны ВСЕГДА ПРОГРАММИРОВАТЬ цепи УСЛОВИЙ таким образом, что, менее дорогой или большинство Исключив УСЛОВИЕ получает оценку ПЕРВОГО, ИЛИ ARRANGE состояние, в таким образом, что может занять максимальную пользу от короткого замыкания

+0

Причина Downvote: всегда проверяйте вещи на реальном сервере с реалистичными данными. Кажется, мой предыдущий комментарий съел. – Jasmine

0

Вот демо, чтобы доказать, что MySQL делает выполнить ИНЕКЕ закорачивания:

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 

Приведенные выше показывает, что медленная функция выполняется несколько раз, когда он появляется на левой стороне условие OR, когда другой операнд ISN» t всегда верно (из-за короткого замыкания).

+1

Хмм, что вы, вероятно, хотели сказать * «Вот демонстрация, доказывающая, что MySQL выполняет короткое замыкание WHERE в этом конкретном случае **:« * –

+0

Конечно, это просто доказательство того, что это может произойти. –

Смежные вопросы