Как оптимизировать использование предложения «ИЛИ» при использовании с параметрами (SQL Server 2008) - PullRequest
8 голосов
/ 29 января 2010

Интересно, есть ли какой-нибудь разумный способ переписать следующий запрос так, чтобы индексы по столбцам использовались оптимизатором?

Create Procedure select_Proc1
    @Key1 int=0,
    @Key2 int=0
As
BEGIN
    Select key3
    From Or_Table
    Where (@key1 =0 OR Key1 =@Key1) AND
          (@key2 =0 OR Key2 =@Key2)
END
GO

Несмотря на то, что столбцы в предложениях WHERE покрыты индексами, SQL Server не может использовать эти индексы. Это поднимает вопрос о том, блокирует ли что-либо использование индексов. Ответ на этот вопрос - да - виновниками являются параметры и условие «ИЛИ». Параметры не охватываются индексами, что означает, что SQL Server не может использовать ни один из индексов для оценки «@ key1 = 0» (условие, которое также применяется к @ key2 = 0). Фактически это означает, что SQL Server не может использовать индексы для оценки предложения «@ key1 = 0 ИЛИ Key1 = @ ключ1» (поскольку предложение «ИЛИ» представляет собой объединение строк, охватываемых обоими условиями). Тот же принцип применим и к другому пункту (re. Key2). Это приводит к тому, что SQL Server приходит к выводу, что никакие индексы не могут использоваться для извлечения строк, а SQL Server использует следующий лучший подход - сканирование кластерных индексов

Как видите, оптимизатор SQL не будет использовать индексы для столбцов, если предикаты имеют значение "ИЛИ" в предложении WHERE. Одним из решений этой проблемы является разделение запросов с помощью предложения IF для всех возможных комбинаций параметров.

Пожалуйста, прочтите эту короткую статью, чтобы получить более полное представление о проблеме: http://www.sql -server-performance.com / articles / per / optimize_or_clause_p1.aspx

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

Ответы [ 4 ]

12 голосов
/ 29 января 2010

SQL Server не очень хорош в оптимизации предикатов OR.

Используйте это:

SELECT  key3
FROM    or_table
WHERE   @key1 = 0
        AND @key2 = 0
UNION ALL
SELECT  key3
FROM    or_table
WHERE   @key1 = 0
        AND @key2 <> 0
        AND key2 = @key2
UNION ALL
SELECT  key3
FROM    or_table
WHERE   @key2 = 0
        AND @key1 <> 0
        AND key1 = @key1
UNION ALL
SELECT  key3
FROM    or_table
WHERE   @key1 <> 0
        AND @key2 <> 0
        AND key1 = @key1
        AND key2 = @key2

SQL Server проверяет значения переменных до выполнения запросов и оптимизирует избыточные запросы.

Это означает, что фактически будет выполнен только один запрос из четырех.

4 голосов
/ 29 января 2010

MSSQL 2008 имеет синтаксис оптимизации упрощения условий, здесь он

 Where (@key1 =0 OR Key1 =@Key1) AND
      (@key2 =0 OR Key2 =@Key2) option(recompile)

Это оптимизирует использование констант

2 голосов
/ 29 января 2010

Вы пробовали табличную функцию?

CREATE FUNCTION select_func1 (  
    @Key1 int=0,
    @Key2 int=0
)
RETURNS TABLE 
AS RETURN (
    Select key3
    From Or_Table
    Where (@key1 =0 OR Key1 =@Key1) AND
          (@key2 =0 OR Key2 =@Key2)
)


select * from select_func1(1,2)
1 голос
/ 30 января 2010

Да - осторожно Использование динамического SQL решит эту проблему. Есть два способа сделать это:

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

б. Если вы проявляете гибкость в отношении расположения этого SQL, вы можете (снова ВНИМАТЕЛЬНО) составить строку запроса в своем приложении и передать ее на сервер.

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

Полная информация от Эрланда Соммарскога: http://www.sommarskog.se/dynamic_sql.html и http://www.sommarskog.se/dyn-search.html

...