Настройка запросов: предикат IN
Пересказ статьи Arthur Daniels. Query tuning: The IN clause
В статье рассматривается предложение IN и другой способ написания аналогичного запроса. Я не собираюсь утверждать, что IN лучше или хуже, чем другие конструкции T-SQL. Я просто хочу продемонстрировать, что он делает.
Перейдем к демонстрации. Я использую для этого StackOverflow2010 и собираюсь создать индекс, который бы использовался запросом.
Да, круто. Давайте взглянем на оператор Index Scan (сканирование индекса).
Я хочу обратить ваше внимание на нижнюю часть. Несмотря на то, что мы не использовали в этом запросе операторов OR, оптимизатор интерпретировал IN как серию OR.
Интересно, как можно оптимизировать наш запрос. Давайте иначе перепишем тот же запрос.
Запрос вернет тот же самый результирующий набор. Теперь давайте запустим оба запроса в одном пакете. Проигнорировав Query Cost (стоимость запроса), просто взглянем на отличия в планах выполнения.
Вот в чем заключается настройка запроса. Переписывание запроса двумя разными способами, чтобы посмотреть, выберет ли оптимизатор другой план выполнения.
Имеется два значительных расхождения в планах этих запросов. Давайте посмотрим на планы выполнения, используя режим сравнения планов выполнения в Management Studio.
Если вам любопытно, выберите полное сравнение. Я объясню разницу ниже. Первый план, использующий IN, расположен слева. Второй план, использующий UNION ALL, находится справа.
Ну, я люблю поговорить о выделении памяти (memory grant). Поэтому начнем отсюда.
План слева, использующий IN, не нуждается в выделении памяти.
На план справа было выделено 1Мб памяти и использовано 248Кб. Это не так плохо, но это важное различие. Если вы испытываете недостаток памяти, то можете отказаться от переписывания своего запроса, чтобы избежать выделения памяти.
Помним, что это тот же пример.
Итак, запрос с UNION ALL был немного быстрее. Когда мы говорим о разнице в 15 миллисекунд, я бы провел больше тестов, прежде чем принять решение. Замечу также, что оценка стоимости для этого плана была выше.
Мы показали, что настройка запроса может быть такой же простой, как переписывание предложения IN. Я не хочу утверждать, какой из способов лучше, поскольку это зависит от ваших условий.
Не переписывайте код, пока нет проблем с производительностью. А если вы это делаете, тщательно тестируйте.
CREATE NONCLUSTERED INDEX ix_DisplayName_Age on Users (DisplayName)
INCLUDE (Age)
SELECT DisplayName
FROM Users as u
WHERE Age IN (96,97,98,99,100)
Да, круто. Давайте взглянем на оператор Index Scan (сканирование индекса).
Я хочу обратить ваше внимание на нижнюю часть. Несмотря на то, что мы не использовали в этом запросе операторов OR, оптимизатор интерпретировал IN как серию OR.
Интересно, как можно оптимизировать наш запрос. Давайте иначе перепишем тот же запрос.
SELECT DisplayName
FROM Users as u
JOIN (SELECT 96 as Age UNION ALL
SELECT 97 as Age UNION ALL
SELECT 98 as Age UNION ALL
SELECT 99 as Age UNION ALL
SELECT 100 as Age ) as A1 on A1.Age = u.Age
Запрос вернет тот же самый результирующий набор. Теперь давайте запустим оба запроса в одном пакете. Проигнорировав Query Cost (стоимость запроса), просто взглянем на отличия в планах выполнения.
Вот в чем заключается настройка запроса. Переписывание запроса двумя разными способами, чтобы посмотреть, выберет ли оптимизатор другой план выполнения.
Сравнение предложения IN с UNION ALL
Имеется два значительных расхождения в планах этих запросов. Давайте посмотрим на планы выполнения, используя режим сравнения планов выполнения в Management Studio.
Если вам любопытно, выберите полное сравнение. Я объясню разницу ниже. Первый план, использующий IN, расположен слева. Второй план, использующий UNION ALL, находится справа.
Сравним выделение памяти
Ну, я люблю поговорить о выделении памяти (memory grant). Поэтому начнем отсюда.
План слева, использующий IN, не нуждается в выделении памяти.
На план справа было выделено 1Мб памяти и использовано 248Кб. Это не так плохо, но это важное различие. Если вы испытываете недостаток памяти, то можете отказаться от переписывания своего запроса, чтобы избежать выделения памяти.
Как насчет разницы в CPU?
Помним, что это тот же пример.
Итак, запрос с UNION ALL был немного быстрее. Когда мы говорим о разнице в 15 миллисекунд, я бы провел больше тестов, прежде чем принять решение. Замечу также, что оценка стоимости для этого плана была выше.
Мораль этой публикации
Мы показали, что настройка запроса может быть такой же простой, как переписывание предложения IN. Я не хочу утверждать, какой из способов лучше, поскольку это зависит от ваших условий.
Не переписывайте код, пока нет проблем с производительностью. А если вы это делаете, тщательно тестируйте.
Обратные ссылки
Автор не разрешил комментировать эту запись
Комментарии
Показывать комментарии Как список | Древовидной структурой