getdate()
は実行時定数関数であり、関数参照ごとに1回だけ評価されるため、
SELECT GETDATE()
FROM SomeBigTable
クエリの実行にかかる時間に関係なく、すべての行で同じ結果が返されます。
ただし、この2つには違いがあります。最初のものは変数を使用し、変数がSQL Serverに割り当てられる前にプランがコンパイルされるため、(再コンパイルがない場合)行の30%が返されると想定されます。この推測により、2番目のクエリとは異なるプランが使用される可能性があります。
フィルタで直接使用する場合は、コンパイル時GETDATE()
に評価さGETDATE()
れ、その後、クエリやデータを変更して再コンパイルをトリガーしなくても、選択性が大幅に変わる可能性があることに注意してください。以下の例では、1,000行のテーブルに対して、変数を使用したクエリは推定300行と全表スキャンのプランにつながりますが、関数呼び出しが埋め込まれたクエリは1行を推定し、ブックマークルックアップを実行します。これは最初の実行では正確ですが、時間の経過により2回目の実行ではすべての行が適格になり、1,000回のランダムルックアップを実行することになります。
USE tempdb;
CREATE TABLE [myTable]
(
CreatedDate datetime,
Filler char(8000) NULL
)
CREATE NONCLUSTERED INDEX ix ON [myTable](CreatedDate)
INSERT INTO [myTable](CreatedDate)
/*Insert 1 row that initially qualifies*/
SELECT DATEADD(D,-2001,getdate())
UNION ALL
/*And 999 rows that don't initially qualify*/
SELECT TOP 999 DATEADD(minute,1, DATEADD(D,-2000,getdate()))
FROM master..spt_values
EXEC('
DECLARE @myDate DATETIME = DATEADD(D,-2000,getdate())
SELECT *
FROM [myTable]
WHERE CreatedDate <= @myDate
')
EXEC('
SELECT *
FROM [myTable]
WHERE CreatedDate <= DATEADD(D,-2000,getdate())
')
RAISERROR ('Delay',0,1) WITH NOWAIT
WAITFOR DELAY '00:01:01'
EXEC('
DECLARE @myDate DATETIME = DATEADD(D,-2000,getdate())
SELECT *
FROM [myTable]
WHERE CreatedDate <= @myDate
')
EXEC('
SELECT *
FROM [myTable]
WHERE CreatedDate <= DATEADD(D,-2000,getdate())
')
DROP TABLE [myTable]