getdate()
はruntime constant functionであり、唯一の
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]
各行のDATEADDは計算されません。 選択偶数がデータを取り出す前に計算されます。 –
類似の質問はここにあります:http://stackoverflow.com/questions/7301058/does-sql-server-optimize-dateadd-calculation-in-select-query –