2012-03-28 96 views
2

第一個查詢是:有人可以解釋兩個查詢之間的區別嗎?

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

第二個查詢是:

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

我想到的是,第一查詢可能是因爲速度更快,「DATEADD」函數計算一次。但實際上這個查詢是相等的(2秒,30000行)

+0

它不計算DATEADD每一行的位置。 在選擇甚至開始提取數據之前計算。 – 2012-03-28 10:38:45

+0

相似的問題在這裏:http://stackoverflow.com/questions/7301058/does-sql-server-optimize-dateadd-calculation-in-select-query – 2012-03-28 10:45:53

回答

3

getdate()runtime constant function,每個函數引用這就是爲什麼

SELECT GETDATE() 
FROM SomeBigTable 

將返回相同的結果爲所有行無論查詢需要多長時間運行只計算一次。

然而,兩者之間存在差異。由於第一個使用變量,並且在將變量分配給SQL Server之前編譯計劃(在沒有重新編譯的情況下),假定將返回30%的行。這種猜測可能會導致它使用與第二個查詢不同的計劃。

直接在過濾器中使用GETDATE()時需要注意的一點是,它在編譯時評估GETDATE(),此後可能在沒有查詢或數據更改的情況下顯着改變選擇性以觸發重新編譯。在下面的示例中,對於1000行表,使用變量的查詢會導致計劃帶有估計的300行和全表掃描,而嵌入函數調用的查詢會估計1行並執行書籤查找。這在第一次運行時是準確的,但是在第二次運行中,由於時間流逝,現在所有行都有資格,並且最終會執行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 2012-03-28 10:49:06

+0

@Yara - 取決於選擇性。如果查詢是高度選擇性的,那麼第二個查詢可能會考慮一個帶有關鍵查找的計劃,這在30%的假設下是不太可能的。 – 2012-03-28 10:51:16

+0

事實上,如果你的謂詞使用少於(即''Where CreatedDate <= DATEADD(D,-2000,getdate())'),那麼事情會更有趣,因爲受影響的估計行將在編譯時確定,但隨着時間的推移該查詢將變得更少選擇性和不太理想。假設沒有數據更改,則不會觸發統計信息重新編譯來糾正此問題。 – 2012-03-28 11:09:02

1

SQL不會重新計算每一行的DATEADD。無論哪種方式,它都會計算一次,然後對您的表格中的行進行比較。兩種不同的方式,一種(可能是不必要的)比另一種更冗長,但最終他們會得到相同的結果。

0

SQL服務器優化器正在幫助使後者查詢更優化。

看一看query plan

相關問題