Выберите порядок оценки «где пункт» - PullRequest
26 голосов
/ 27 января 2009

В Sql Server 2005, когда у меня несколько параметров, у меня есть гарантия, что порядок оценки будет всегда слева направо?

Используя пример:

select a from table where c=1 and d=2

В этом запросе, если условие "c = 1" не выполняется, условие "d = 2" никогда не будет оцениваться?

PS- "c" - это столбец с целочисленными индексами, d - это большой столбец типа varchar и не индексируемый, который требует полного сканирования таблицы

обновление Я пытался избежать выполнения двух запросов или условных выражений, мне просто нужно что-то вроде: если «условие c» не выполнено, есть способ избежать выполнения тяжелого условия «d», поскольку нужен в моем случае.

Ответы [ 7 ]

29 голосов
/ 27 января 2009

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

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

Однако, если он определяет, что индекс на c не очень избирателен (хотя и не в вашем примере, столбец пола редко индексируется с пользой), он все равно может принять решение о сканировании таблицы.

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

4 голосов
/ 27 января 2009

SQL Server будет генерировать оптимизированный план для каждого выполняемого оператора. Вам не нужно заказывать пункт «Где», чтобы получить эту выгоду. Единственное, что у вас есть, это то, что он будет выполнять операторы в следующем порядке:

SELECT A FROM B WHERE C
SELECT D FROM E WHERE F

будет запускать первую строку перед второй.

2 голосов
/ 04 ноября 2009

Короткое замыкание происходит, когда условие, на которое мы ссылаемся, включает только литералы или константы. Например, предположим, у нас есть таблица TableA, в которой есть столбец num со всеми положительными числами от 1 до 10, а затем, если я напишу этот запрос.

Выберите номер из таблицы A, ГДЕ TableA.num <0 И 1/0 = 10. </p>

Это приведет к ошибке.

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

2 голосов
/ 27 января 2009

Если вы хотите быть уверенным, вы можете проверить План выполнения запроса . План выполнения, который MSSQL создает / оптимизирует, достаточно умен, чтобы проверить индексированный столбец перед столбцом varchar.

2 голосов
/ 27 января 2009

Вы можете посмотреть на план выполнения запроса и определить, что он на самом деле пытается сделать. Я думаю, что механизм запросов SQL Server должен выполнять этот тип сканирования и будет разумно преобразовывать его в операции. Например, если вы выполните «дорогой оператор и ложь», он быстро оценивается как ложный.

Из того, что я узнал, что вы печатаете, (и может быть) отличается от того, что на самом деле выполняется. Вы просто сообщаете серверу, какого типа результатов вы ожидаете. То, как он получает ответ, не соотносится слева направо от кода, который вы предоставляете.

1 голос
/ 27 января 2009

Оптимизатор запросов MS SQL Server делает короткое замыкание, да. Гарантированный.

Запустите это:

select 1 where 1 = 0 and 1 / 0 = 10

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

1 голос
/ 27 января 2009

Одним из способов управления порядком оценки является выражение CASE.

[Изменить]

Популярное мнение, которое я пытался выразить, было:

Вы не можете зависеть от порядка вычисления выражений для таких вещей, как «ГДЕ ИЛИ», так как оптимизатор может выбрать план который оценивает второй предикат перед первым. Но порядок вычисления выражений в операторе CASE фиксирован, так что вы можете зависеть от детерминированной оценки короткого замыкания CASE заявление.

Это немного сложнее, чем объяснено на сайте ниже:

http://blogs.msdn.com/b/bartd/archive/2011/03/03/don-t-depend-on-expression-short-circuiting-in-t-sql-not-even-with-case.aspx

...