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'関数が1回計算するため、最初のクエリの方が高速になると思います。しかし実際には、このクエリは両方とも等しい(2秒、30 000行)

4

3 に答える 3

3

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]
于 2012-03-28T10:45:41.990 に答える
1

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

于 2012-03-28T10:36:46.010 に答える
0

SQL Serverオプティマイザーは、後者のクエリをより最適化するのに役立ちます。

クエリプランを見てください。

于 2012-03-28T10:42:31.580 に答える