次のようなクエリがあります。
SELECT col1
FROM MyTable
WHERE
DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
BETWEEN col2
AND col3
;
これにより、次のような実行プランのツールチップが表示されます。

dateadd求める述語の一部は、クエリ内のすべての行に対して実行されますか?または、SQL Serverはクエリ全体の値を1回計算しますか?
次のようなクエリがあります。
SELECT col1
FROM MyTable
WHERE
DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
BETWEEN col2
AND col3
;
これにより、次のような実行プランのツールチップが表示されます。

dateadd求める述語の一部は、クエリ内のすべての行に対して実行されますか?または、SQL Serverはクエリ全体の値を1回計算しますか?
回答:
ランタイム定数として知られている特定の関数は、定数フォールディングと呼ばれるプロセスを通過します。定数を「折りたたむ」ことにより、式はクエリ実行の早い段階で評価され、結果はキャッシュされ、必要に応じてキャッシュされた結果がキャッシュされます。クエリの式はDATEADD(dd, 0, DATEDIFF(dd, 0, getdate()))ランタイム定数なので、クエリごとに1回だけ折りたたまれ、評価されます。
雑学として:展開RAND()可能であると期待される関数は実際には折りたたみ可能であり、予期しない動作が発生します。しかし、たとえばNEWID()、その他は折りたたみ可能ではなく、行ごとに評価を強制します。
実行計画は素晴らしいですが、時には真実を伝えないこともあります。したがって、ここにパフォーマンステストに基づく証明があります。
(そして一番下の行-式はすべての行に対して評価されていません)
;with t(i) as (select 0 union all select i+1 from t where i < 9)
select getdate()-1 as col1,getdate() as col2,getdate() as col3
into #t
from t t0,t t1,t t2,t t3,t t4,t t5,t t6,t t7
(100000000行が影響を受けました)
これはOPクエリであり、実行に約12秒かかります
SELECT col1
FROM #t
WHERE
DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
BETWEEN col2
AND col3
;
実行前にパラメータに日付を保存するこのクエリは、ほぼ同じ時間、12秒かかります。
declare @dt datetime = DATEADD(dd, 0, DATEDIFF(dd, 0, GETDATE()))
SELECT col1
FROM #t
WHERE
@dt
BETWEEN col2
AND col3
;
そして結果を確認するだけ
です-col1で計算を行うこのクエリは、すべての行の式を再計算する必要があるため、実行に約30秒かかります。
SELECT col1
FROM #t
WHERE
DATEADD(dd, 0, DATEDIFF(dd, 0, col1))
BETWEEN col2
AND col3
;
すべてのクエリが繰り返し実行され、ほぼ同じメトリックが表示されました
GETDATE()。