非常に多くの回答がインデックスに言及しているのは不可解です。実際、DATEDIFF
SARGable ではありませんが、CASE WHEN によって SQL Server のクエリ オプティマイザーがインデックスの使用を考慮しないため (カバーするスキャン可能なパスを見つけようとする以外は)、ここではまったく関係ありません。私が知る限り、インデックス パスに対する DATEDIFF 関連の式の候補は、この質問とはまったく無関係です。
実際、CASE
最初の真の述語が見つかると、SQL Server がステートメント内の述語の評価を停止することを示すのは非常に簡単です。
その事実を実証するために、いくつかのサンプル データを作成してみましょう。
CREATE TABLE Diffy (SomeKey INTEGER NOT NULL IDENTITY(1,1), DateOfSale DATE);
DECLARE @ThisOne AS DATE;
SET @ThisONe = '2012-01-01';
WHILE @thisONe < '2013-01-01'
BEGIN
INSERT INTO Diffy (DateOfSale) VALUES(@ThisOne);
SET @ThisOne = DateAdd(d, 1, @ThisOne);
END;
SELECT
それでは、元の質問のパターンにしましょう。元の質問はTOP 10
句なしで句を指定してORDER BY
いるため、実際に返される値はランダムであることに注意してください。しかし、評価を害する句を に追加すると、CASE
何が起こっているかがわかります。
SELECT TOP 10 *, CASE
WHEN datediff(day,DateOfSale, getDate()) > 5 then '5'
WHEN datediff(day,DateOfSale, getDate()) > 10 then '10'
WHEN 1/0 > 1then 'boom'
ELSE '20' END
AS Jack
FROM Diffy;
1/0 > 1
を評価した場合、 のようなものが期待されることに注意してください'Divide by zero error encountered.'
。ただし、サーバーに対してこのクエリを実行すると、すべての列に「5」が含まれる 10 行が生成されJack
ます。
TOP 10 を削除すると、確かにいくつかの行が取得され、Divide by zero
エラーが発生します。したがって、SQL Server が CASE ステートメントで早期終了評価を行っていると結論付けることができます。
それに加えて、ドキュメントには次のようにも書かれています。
CASE ステートメントは、その条件を順番に評価し、条件が満たされた最初の条件で停止します。
DATEDIFF()
おそらく、この質問は、共通の部分式がすべてのCASE
ステートメントから引き上げられ、一度計算されてから、各述語のコンテキスト内で評価されるかどうかを尋ねることを意図しています。の出力を観察するとSET SHOWPLAN_TEXT ON
、そうではないと結論付けることができると思います。
|--Compute Scalar(DEFINE:([Expr1004]=CASE WHEN datediff(day,CONVERT_IMPLICIT(datetimeoffset(7),[Scratch3].[dbo].[Diffy].[DateOfSale],0),CONVERT_IMPLICIT(datetimeoffset(3),getdate(),0))>(5) THEN '5' ELSE CASE WHEN datediff(day,CONVERT_IMPLICIT(datetimeoffset(7),[Scratch3].[dbo].[Diffy].[DateOfSale],0),CONVERT_IMPLICIT(datetimeoffset(3),getdate(),0))>(10) THEN '10' ELSE CASE WHEN (1)/(0)>(1) THEN 'boom' ELSE '20' END END END))
|--Index Scan(OBJECT:([Scratch3].[dbo].[Diffy].[DiffyHelper]))
DATEDIFF()
そのことから、このクエリの構造は、行ごと、述語ごとに評価されることを意味していると結論付けることができますO(rows * predicates)
。これにより、クエリの CPU 負荷がいくらか発生しますが、DATEDIFF()
それほど高価ではなく、あまり気にする必要はありません。実際にパフォーマンスの問題を引き起こしていることが判明した場合は、クエリから計算を手動で引き上げる方法があります。たとえばDATEDIFF()
、比較の日付相対側です。