Почему сравнение переменных T-SQL медленнее, чем сравнение на основе функций GETDATE ()? - PullRequest
8 голосов
/ 01 июля 2011

У меня есть оператор T-SQL, который я запускаю для таблицы с множеством строк.Я вижу странное поведение.Сравнение столбца DateTime с предварительно рассчитанным значением медленнее, чем сравнение каждой строки с вычислением, основанным на функции GETDATE ().

Следующий SQL занимает 8 секунд:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
GO
DECLARE @TimeZoneOffset int = -(DATEPART("HH", GETUTCDATE() - GETDATE()))
DECLARE @LowerTime DATETIME = DATEADD("HH", ABS(@TimeZoneOffset), CONVERT(VARCHAR, GETDATE(), 101) + ' 17:00:00')
SELECT TOP 200 Id, EventDate, Message 
FROM Events WITH (NOLOCK)
WHERE EventDate > @LowerTime
GO

Это чередование странномгновенно возвращает:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
GO
SELECT TOP 200 Id, EventDate, Message 
FROM Events WITH (NOLOCK)
WHERE EventDate > GETDATE()-1
GO

Почему второй запрос намного быстрее?

РЕДАКТИРОВАНИЕ: Я обновил SQL, чтобы точно отразить другие настройки, которые я использую

Ответы [ 2 ]

9 голосов
/ 19 октября 2011

После долгих чтений и исследований я обнаружил, что проблема заключается в перехвате параметров. Sql Server пытается определить, как лучше всего использовать индексы, основываясь на предложении where, но в этом случае он не очень хорошо работает.

См. Примеры ниже:

Медленная версия:

declare @dNow DateTime  
Select @dNow=GetDate()  
Select *  
From response_master_Incident rmi  
Where rmi.response_date between DateAdd(hh,-2,@dNow) AND @dNow  

Быстрая версия:

Select *  
From response_master_Incident rmi  
Where rmi.response_date between DateAdd(hh,-2,GetDate()) AND GetDate()  

«Быстрая» версия работает примерно в 10 раз быстрее, чем медленная. Поле Response_Date проиндексировано и имеет тип DateTime.

Решение состоит в том, чтобы сообщить Sql Server, как лучше всего оптимизировать запрос. Изменение примера следующим образом для включения опции OPTIMIZE привело к тому, что он использовал тот же план выполнения, что и «Быстрая версия». Опция OPTMIZE здесь явно указывает серверу sql обрабатывать локальную переменную @dNow как дату (как если бы объявление ее как DateTime было недостаточно: s)

При этом следует соблюдать осторожность, поскольку в более сложных предложениях WHERE запрос может оказаться хуже, чем собственные оптимизации Sql Server.

declare @dNow DateTime

SET @dNow=GetDate()

Select ID, response_date, call_back_phone 
from response_master_Incident rmi
where rmi.response_date between DateAdd(hh,-2,@dNow) AND @dNow

-- The optimizer does not know too much about the variable so assumes to should perform a clusterd index scann (on the clustered index ID) - this is slow

-- This hint tells the optimzer that the variable is indeed a datetime in this format (why it does not know that already who knows)
OPTION(OPTIMIZE FOR (@dNow = '99991231'));
0 голосов
/ 13 июля 2011

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

С другой стороны, функция getdate оценивается во время выполнения, поэтому план выполнения создается с использованием статистики для этого конкретногодата, которая, конечно, более реалистична, чем предыдущие.

Если вы создадите хранимую процедуру с параметром @LowerTime, вы получите лучшие результаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...