2012-03-28 10 views
2

最初のクエリは次のとおりです。誰かが2つのクエリの違いを説明できますか?

declare @myDate datetime = DATEADD(D,-2000,getdate()) 
SELECT * FROM [myTable] 
where CreatedDate >= @myDate 

2番目のクエリは次のとおりです。

SELECT * FROM [myTable] 
where CreatedDate >= DATEADD(D,-2000,getdate()) 

私は最初のクエリがより速くなることを期待して、なぜなら「DATEADD」関数のは一回計算します。しかし、実際にはこのクエリは両方とも等しい(2秒、30 000行)

+0

各行のDATEADDは計算されません。 選択偶数がデータを取り出す前に計算されます。 –

+0

類似の質問はここにあります:http://stackoverflow.com/questions/7301058/does-sql-server-optimize-dateadd-calculation-in-select-query –

答えて

3

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] 
+0

これは、最初の変種が少し時間がかかることを意味しますか? – Yara

+0

@Yara - 選択性に依存します。問合せが高度に選択的であった場合、2番目の問合せでは、30%の前提の下ではほとんど起こりそうにないキー・ルックアップを持つ計画を検討することがあります。 –

+0

実際にあなたの述語がより小さい(つまり 'CreatedDate <= DATEADD(D、-2000、getdate())')を使用していた場合、影響を受ける見積もられた行はコンパイル時に決定されますが、クエリの選択性が低く、最適性が低くなります。データを変更しないと仮定すると、これを修正するために統計再コンパイルがトリガーされません。 –

1

SQLは1行ごとにDATEADDを再計算しません。いずれにしても、それを一度計算してから、テーブルの行全体の結果との比較を実行します。 2つの異なる方法(おそらく不必要に)他の方法よりも冗長ですが、結局は同じ結果が得られます。

0

SQLサーバーオプティマイザは、後者のクエリの最適化を支援しています。

query planをご覧ください。

関連する問題