Загадка производительности запросов T-SQL: почему переменная имеет значение? - PullRequest
12 голосов
/ 19 февраля 2010

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

Например, для запуска требуется 336 мс:

Declare @InstanceID int set @InstanceID=1;
With myResults as (
    Select 
        Row = Row_Number() Over (Order by sv.LastFirst), 
        ContactID
    From DirectoryContactsByContact(1) sv 
    Join ContainsTable(_s_Contacts, SearchText, 'john') fulltext on (fulltext.[Key]=ContactID)
    Where IsNull(sv.InstanceID,1) = @InstanceID
    and len(sv.LastFirst)>1
) Select * From myResults Where Row between 1 and 20;  

Если я заменю @InstanceID жестко запрограммированным числом, для запуска потребуется более 13 секунд (13890 мс):

Declare @InstanceID int set @InstanceID=1;
With myResults as (
    Select 
        Row = Row_Number() Over (Order by sv.LastFirst), 
        ContactID
    From DirectoryContactsByContact(1) sv 
    Join ContainsTable(_s_Contacts, SearchText, 'john') fulltext on (fulltext.[Key]=ContactID)
    Where IsNull(sv.InstanceID,1) = 1
    and len(sv.LastFirst)>1
) Select * From myResults Where Row between 1 and 20;  

В других случаях я получаю прямо противоположный эффект: например, использование переменной @s вместо литерала 'john' заставляет запрос выполняться медленнее на порядок.

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

Ответы [ 2 ]

2 голосов
/ 19 февраля 2010

Причиной может быть то, что IsNull(sv.InstanceID,1) = @InstanceID является очень избирательным для некоторых значений @InstanceID, но не очень избирательным для других.Например, с InstanceID = null могут быть миллионы строк, поэтому для @InstanceID = 1 сканирование может быть быстрее.

Но если вы явно укажете значение @InstanceID, SQL Server узнает на основе таблицыстатистика выборочная или нет.

Сначала убедитесь, что ваша статистика актуальна:

UPDATE STATISTICS table_or_indexed_view_name 

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

0 голосов
/ 04 июля 2012

С жестко закодированными значениями оптимизатор знает, на чем основываться при построении плана выполнения. Когда вы используете переменные, он пытается «угадать» значение, и во многих случаях он получает не самое лучшее.

Вы можете помочь ему выбрать значение для оптимизации двумя способами:

  1. «Я знаю лучше», это заставит его использовать предоставленное вами значение.

    ОПЦИЯ (ОПТИМИЗАЦИЯ ДЛЯ (@ InstanceID = 1))

  2. «Посмотрите, что я делаю», это заставит его перехватывать передаваемые вами значения и использовать среднее (или наиболее популярное для некоторых типов данных) значение, представленное с течением времени.

    ВАРИАНТ (ОПТИМИЗИРОВАТЬ ДЛЯ НЕИЗВЕСТНЫХ)

...