SQL Server оптимизирует вычисление DATEADD в запросе выбора? - PullRequest
4 голосов
/ 04 сентября 2011

У меня такой запрос на Sql Server 2008:

DECLARE @START_DATE DATETIME
SET @START_DATE = GETDATE()

SELECT * FROM MY_TABLE
WHERE TRANSACTION_DATE_TIME > DATEADD(MINUTE, -1440, @START_DATE)

В запросе выбора, который вы видите выше, оптимизирует ли SqlServer запрос, чтобы не вычислять результат DATEADD снова и снова.Или я несу ответственность за сохранение результата DATEADD во временной переменной?

Ответы [ 3 ]

10 голосов
/ 04 сентября 2011

Функции SQL Server, которые считаются константами времени выполнения , оцениваются только один раз.GETDATE() является такой функцией, а DATEADD(..., constant, GETDATE()) также является константой времени выполнения.Оставляя фактический вызов функции внутри запроса, вы позволяете оптимизатору увидеть, какое значение будет фактически использоваться (в отличие от сниффинга значения переменной), а затем он может соответствующим образом скорректировать свои оценки мощности, возможно, придумав лучший план.

Также прочтите это: Устранение неполадок при низкой производительности запросов: сворачивание констант и оценка выражений во время оценки мощности .

@ Martin Smith

Вы можетевыполните этот запрос:

set nocount on;
declare @known int;
select @known = count(*) from sysobjects;
declare @cnt int = @known;
while @cnt = @known
    select @cnt = count(*) from sysobjects where getdate()=getdate()
select @cnt, @known;

В моем случае через 22 секунды он достиг граничного случая и цикл завершился.Важно, что цикл завершился с @cnt ноль .Можно было бы ожидать, что если getdate() вычисляется для каждой строки, то мы получим @cnt, отличный от правильного числа @known, но не 0. Тот факт, что @cnt равен нулю, когда цикл существует, показывает, что каждый getdate() был оцененодин раз, а затем одно и то же постоянное значение использовалось для каждой строки, ГДЕ фильтрующейся (не совпадающей).Мне известно, что один положительный пример не доказывает теорему, но я думаю, что дело достаточно убедительное.

8 голосов
/ 04 сентября 2011

Удивительно, но я обнаружил, что использование встроенного метода GETDATE () кажется более эффективным, чем выполнение этого типа расчетов заранее.

DECLARE @sd1 DATETIME, @sd2 DATETIME;
SET @sd1 = GETDATE();

SELECT * FROM dbo.table
WHERE datetime_column > DATEADD(MINUTE, -1440, @sd1)

SELECT * FROM dbo.table
WHERE datetime_column > DATEADD(MINUTE, -1440, GETDATE())

SET @sd2 = DATEADD(MINUTE, -1440, @sd1);

SELECT * FROM dbo.table
WHERE datetime_column > @sd2;

Если вы проверите планы на них, средний запрос всегда будет иметь наименьшую стоимость (но не всегда наименьшее затраченное время). Конечно, это может зависеть от ваших индексов и данных, и вы не должны делать никаких предположений, основанных на одном запросе, что такая же упреждающая оптимизация будет работать для другого запроса. Моим инстинктом было бы не выполнять никаких встроенных вычислений, а вместо этого использовать приведенный выше вариант @sd2 ... но я узнал, что не могу доверять своему инстинкту все время и не могу делать общие предположения на основе поведения Я испытываю в определенных сценариях.

3 голосов
/ 04 сентября 2011

Будет выполнено только один раз. Вы можете дважды проверить это, проверив план выполнения («Вычислить скаляр» -> Расчетное количество выполнения == 1)

...