После долгих чтений и исследований я обнаружил, что проблема заключается в перехвате параметров. 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'));