Подтвердить что ты не робот

Задача производительности запросов T-SQL: почему использование переменной имеет значение?

Я пытаюсь оптимизировать сложный 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" заставляет запрос запускаться медленнее на порядок.

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

4b9b3361

Ответ 1

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

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

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

UPDATE STATISTICS table_or_indexed_view_name 

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

Ответ 2

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

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

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

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

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

    ОПЦИЯ (ОПТИМИЗАЦИЯ НЕИЗВЕСТНО)