SQL Server предикаты ленивый? - PullRequest
8 голосов
/ 04 марта 2011

У меня есть запрос:

SELECT 
    someFields 
FROM 
    someTable 
WHERE 
    cheapLookup=1 
    AND (CAST(someField as FLOAT)/otherField)<0.9

Итак, будет ли выполняться CAST и деление в случае, если cheapLookup равно 0?Если нет, как я могу избежать расчета в этом случае?

Ответы [ 4 ]

14 голосов
/ 04 марта 2011

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

Если предикат 'cheapLookup = 1' может использовать индекс, и этодостаточно избирательно, SQL Server, скорее всего, выберет поиск по этому индексу и применит второй предикат в качестве остатка (то есть, оценивая его только в строках, которые соответствуют операции поиска).

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

Второй предикат не будет выбран для поискаоперации, если только не будет индексированный вычисляемый столбец во всем выражении, и использование этого индекса оказывается самым дешевым способом выполнения всего запроса.Если подходящий индекс существует, SQL Server будет искать «второй результат предиката <0,9» и применять «cheapLookup = 1» в качестве остатка.Существует также вероятность того, что индексированный вычисляемый столбец имеет в качестве второго ключа cheapLookup, что приведет к чистому поиску без остатка. </p>

Еще одна вещь, связанная со вторым предикатом, заключается в том, что без вычисляемого столбца (или не индексируется), SQL Server придется угадывать селективность выражения.С вычисляемым столбцом сервер может создавать статистику по столбцу выражения-результата, что поможет оптимизатору.Обратите внимание, что вычисляемый столбец «CAST (someField as FLOAT) / otherField» должен быть сохранен до того, как его можно будет проиндексировать или создать для него статистику, поскольку он содержит неточный тип данных.

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

6 голосов
/ 04 марта 2011

SQL является декларативным: вы указываете базе данных, что вы хотите, а не как вы хотите, чтобы это было сделано. База данных полностью бесплатна для оценки лениво или охотно. На самом деле, он может оценить трижды в обратном порядке для всех, что я знаю:)

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

declare @t table (id int, someField float, otherField float)
insert @t select id, someField, otherField from someTable 
    where cheaplLookup <> 1
delete @t where (CAST(someField as FLOAT)/otherField) >= 0.9
insert @t select id, someField, otherField from someTable 
    where cheaplLookup = 1

В вашем примере я бы ожидал, что SQL Server выберет лучший способ без каких-либо подсказок или уловок.

2 голосов
/ 04 марта 2011

То, что вы имеете в виду, это короткое замыкание, как и поддержка других языков (например, C #).

Я считаю, что SQL Server может закорачиваться, но зависит от сценария / того, что происходит в оптимизаторе, поэтому, конечно, нет гарантии, что это произойдет. Это просто может .

Отличная ссылка на это Ремуса Русану здесь:
http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/

2 голосов
/ 04 марта 2011

Это зависит от того, как SQL Server оптимизирует запрос, вы можете запустить Query Analyzer, чтобы увидеть для вашего конкретного случая

Верный способ оптимизации сказал бы

    WITH QueryResult AS (
    SELECT 
        someFields 
    FROM 
        someTable 
    WHERE 
        cheapLookup=1 
    )

SELECT * FROM QueryResult WHERE (CAST(someField as FLOAT)/otherField)<0.9
...