Оцениваются ли логические выражения в предложениях SQL WHERE для короткого замыкания ?
Например:
SELECT *
FROM Table t
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key)
Если @key IS NULL оценивается как истина, оценивается ли @key IS NOT NULL И @key = t.Key ?
Если нет, то почему?
Если да, то гарантируется ли это? Является ли это частью ANSI SQL или зависит от базы данных?
Если конкретная база данных, SqlServer? Оракул? MySQL?
sql
short-circuiting
Грег Дин
источник
источник
WHERE a = 1 AND b = 2
это может быть эффективным для механизма базы данных, сначала найти все строки, где b = 2, а затем отфильтровать, где a = 1. Если вы попросите гарантии, тогда оптимизатор станет бесполезным.Ответы:
ANSI SQL Draft 2003 5WD-01-Framework-2003-09.pdf
источник
CASE
, закорочен.Из вышесказанного, короткое замыкание на самом деле недоступно.
Если вам это нужно, я предлагаю оператор Case:
Where Case when Expr1 then Expr2 else Expr3 end = desiredResult
Expr1
всегда оценивается, но только один изExpr2
иExpr3
будет оцениваться для каждой строки.источник
Думаю, это один из тех случаев, когда я бы написал его так, как будто он не замыкался, по трем причинам.
Поскольку для MSSQL это не решается путем взгляда на BOL в очевидном месте, поэтому для меня это делает его канонически неоднозначным.
потому что, по крайней мере, тогда я знаю, что мой код будет работать. И что более важно, так же поступят и те, кто придет за мной, поэтому я не заставляю их беспокоиться об одном и том же вопросе снова и снова.
Я пишу достаточно часто для нескольких продуктов СУБД, и я не хочу вспоминать о различиях, если я могу легко их обойти.
источник
Я не верю, что короткое замыкание в SQL Server (2005) гарантировано. SQL Server выполняет ваш запрос через свой алгоритм оптимизации, который принимает во внимание множество вещей (индексы, статистику, размер таблицы, ресурсы и т. Д.), Чтобы разработать эффективный план выполнения. После этой оценки вы не можете с уверенностью сказать, что ваша логика короткого замыкания гарантирована.
Некоторое время назад я сам столкнулся с тем же вопросом, и мое исследование действительно не дало мне окончательного ответа. Вы можете написать небольшой запрос, чтобы получить представление о том, что он работает, но можете ли вы быть уверены, что по мере увеличения нагрузки на вашу базу данных таблицы будут расти, и все будет оптимизировано и изменено в базе данных, этот вывод будет держать. Я не мог и поэтому проявил осторожность и использовал CASE в предложении WHERE, чтобы гарантировать короткое замыкание.
источник
Вы должны помнить, как работают базы данных. Учитывая параметризованный запрос, база данных строит план выполнения на основе этого запроса без значений параметров. Этот запрос используется каждый раз, когда он запускается, независимо от фактических предоставленных значений. Замыкание запроса с определенными значениями не имеет значения для плана выполнения.
источник
Я обычно использую это для необязательных параметров. Это то же самое, что короткое замыкание?
SELECT [blah] FROM Emp WHERE ((@EmpID = -1) OR (@EmpID = EmpID))
Это дает мне возможность передать -1 или что-то еще, чтобы учесть необязательную проверку атрибута. Иногда это связано с объединением нескольких таблиц или, желательно, представления.
Очень удобно, но не совсем уверен в дополнительной работе, которую он дает движку db.
источник
Что касается SQL Server, я думаю, это зависит от версии, но мой опыт работы с SQL Server 2000 показывает, что он по-прежнему оценивает @key = t.Key, даже если @key имеет значение null. Другими словами, он не выполняет эффективного короткого замыкания при оценке предложения WHERE.
Я видел, как люди рекомендовали структуру, подобную вашему примеру, как способ выполнения гибкого запроса, при котором пользователь может вводить или не вводить различные критерии. По моим наблюдениям, Key все еще участвует в плане запроса, когда @key имеет значение null, и если Key проиндексирован, он не использует индекс эффективно.
Этот вид гибких запросов с различными критериями, вероятно, является одним из случаев, когда динамически создаваемый SQL - действительно лучший способ. Если @key имеет значение null, вы просто не включаете его в запрос вообще.
источник
Просто наткнулся на этот вопрос и уже нашел эту запись в блоге: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/
SQL-сервер может оптимизировать запрос в любом месте, где он считает нужным, поэтому в примере, приведенном в сообщении блога, вы не можете полагаться на короткое замыкание.
Тем не менее, очевидно, что CASE задокументирован для оценки в письменном порядке - проверьте комментарии к этому сообщению в блоге.
источник
Основная характеристика оценки короткого замыкания заключается в том, что она прекращает вычисление выражения, как только может быть определен результат. Это означает, что остальную часть выражения можно игнорировать, потому что результат будет одинаковым независимо от того, оценивается он или нет.
Двоичные логические операторы являются коммутативными, что означает:
поэтому нет никакой гарантии относительно порядка оценки. Порядок оценки будет определяться оптимизатором запросов.
В языках с объектами могут быть ситуации, когда вы можете писать логические выражения, которые могут быть вычислены только с помощью вычисления короткого замыкания. Конструкция вашего примера кода часто используется на таких языках (C #, Delphi, VB). Например:
Этот пример C # вызовет исключение, если
someString == null
он будет полностью оценен. При оценке короткого замыкания он будет работать каждый раз.SQL работает только со скалярными переменными (без объектов), которые нельзя неинициализировать, поэтому нет способа написать логическое выражение, которое нельзя вычислить. Если у вас есть какое-то значение NULL, любое сравнение вернет false.
Это означает, что в SQL вы не можете написать выражение, которое по-разному оценивается в зависимости от использования короткого замыкания или полной оценки.
Если реализация SQL использует оценку короткого замыкания, можно только надеяться, что она ускорит выполнение запроса.
источник
я не знаю о коротких кругах, но я бы написал это как утверждение 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
источник
Ниже представлен быстрый и грязный тест на 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)
отсутствие записи удовлетворяет этому условию:
Это заняло несколько секунд, что указывало на то, что поведение короткого замыкания больше не существовало, и сложная операция оценивалась для каждой записи.
Надеюсь, это поможет, ребята.
источник
Вот демонстрация, чтобы доказать, что 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
Выше показано, что медленная функция выполняется больше раз, когда она появляется слева от условия ИЛИ, когда другой операнд не всегда верен (из-за короткого замыкания).
источник
Это занимает дополнительные 4 секунды в анализаторе запросов, поэтому из того, что я вижу, IF даже не закорочен ...
SET @ADate = NULL IF (@ADate IS NOT NULL) BEGIN INSERT INTO #ABla VALUES (1) (SELECT bla from a huge view) END
Было бы неплохо иметь гарантированный способ!
источник
Но очевидно, что сервер 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'
здесь первое условие будет оцениваться как ложное, и, следовательно, СУБД перейдет ко второму условию, и вы снова получите ошибку преобразования, как в примере выше.
ПРИМЕЧАНИЕ. Я НАПИСАЛ ОШИБОЧНОЕ СОСТОЯНИЕ, ЧТОБЫ УЗНАТЬ, ПОГОДА ВЫПОЛНЯЕТСЯ ИЛИ ЗАКОНЧИВАЕТСЯ, ЕСЛИ РЕЗУЛЬТАТ ЗАПРОСА В ОШИБКЕ СОЗДАЕТ, ЧТО СОСТОЯНИЕ ВЫПОЛНЕНО, КОРОТКО ЗАВЕРШЕНО ИНАЧЕ.
ПРОСТОЕ ОБЪЯСНЕНИЕ
Рассмотреть возможность,
поскольку первое условие оценивается как ИСТИНА , бессмысленно оценивать второе условие, потому что его оценка в любом значении не повлияет на результат вообще, поэтому для Sql Server это хорошая возможность сэкономить время выполнения запроса, пропустив ненужную проверку или оценку условий .
в случае «ИЛИ», если первое условие оценивается как ИСТИНА, вся цепочка, соединенная «ИЛИ», будет считаться оцененной как истинное без оценки других.
если условие1 оценивается как истинное, оставьте все условия до тех пор, пока условиеN не будет пропущено. В общих словах при определении первого ИСТИНА все остальные условия, связанные оператором ИЛИ, будут пропущены.
Рассмотрим второе условие
поскольку первое условие оценивается как FALSE, бессмысленно оценивать второе условие, потому что его оценка в любом значении не повлияет на результат вообще, поэтому снова это хорошая возможность для Sql Server сэкономить время выполнения запроса, пропустив ненужную проверку или оценку условий .
в случае «И», если первое условие оценивается как ЛОЖЬ, вся цепочка, связанная с «И», будет считаться оцененной как ЛОЖЬ без оценки других.
если условие1 оценивается как ЛОЖЬ , оставьте все условия до тех пор, пока условиеN не будет пропущено. В общих словах при определении первого значения FALSE все остальные условия, связанные AND , будут пропущены.
ПОЭТОМУ РАЗУМНЫЙ ПРОГРАММАТОР ДОЛЖЕН ВСЕГДА ПРОГРАММИРОВАТЬ ЦЕПЬ УСЛОВИЙ ТАКИМ ОБРАЗОМ, ЧТОБЫ, МЕНЬШЕ ДОРОГОЕ ИЛИ НАИБОЛЕЕ ИСКЛЮЧАЮЩЕЕ УСЛОВИЕ ПЕРВОЕ ОЦЕНИВАЕТСЯ, ИЛИ СОЗДАТЬ СОСТОЯНИЕ ТАКИМ ОБРАЗОМ, ЧТО МОЖНО ИЗБЕЖАТЬ
источник