2009-01-07 99 views
6

在開發新的查詢時,我編寫了它並在SQL查詢分析器中對其進行了分析。查詢表現非常好,沒有任何表掃描,但是當我將其封裝在存儲過程中時,性能非常糟糕。當我查看執行計劃時,我可以看到SQL Server選擇了一個不同的計劃,它使用表掃描而不是TableB上的索引查找(我已經強制混淆了表和列名,但沒有查詢邏輯已經改變)。直接執行語句和從存儲過程執行語句時的不同執行計劃

這裏的查詢

SELECT  
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)) AS Day, 
    DATEPART(hh, TableA.Created) AS [Hour], 
    SUM(TableB.Quantity) AS Quantity, 
    SUM(TableB.Amount) AS Amount 
FROM 
    TableA 
    INNER JOIN TableB ON TableA.BID = TableB.ID 
WHERE  
    (TableA.ShopId = @ShopId) 
GROUP BY 
    DATEADD(dd, 0, DATEDIFF(dd, 0, TableA.Created)), 
    DATEPART(hh, TableA.Created) 
ORDER BY 
    DATEPART(hh, TableA.Created) 

當我運行查詢「原始」我得到了下面的跟蹤統計

 
Event Class   Duration CPU Reads Writes 
SQL:StmtCompleted 75  41  7  0 

當我使用下面的命令

運行查詢作爲存儲過程
DECLARE @ShopId int 
SELECT @ShopId = 1 
EXEC spStats_GetSalesStatsByHour @ShopId 

我收到以下跟蹤統計

 
Event Class   Duration CPU Reads Writes 
SQL:StmtCompleted 222  10  48  0 

我也得到了同樣的結果,如果我存儲查詢在一個nvarchar和使用sp_executesql如下執行(它執行如存儲過程)

DECLARE @SQL nvarchar(2000) 
SET @SQL = 'SELECT DATEADD(dd, ...' 
exec sp_executesql @SQL 

該存儲過程並不包含除什麼上面的select語句。什麼會導致sql server僅僅因爲語句被作爲存儲過程執行而選擇劣質執行計劃?

目前,我們正在的SQL Server 2000

回答

13

上運行這通常有事情做與參數嗅探。處理可能非常令人沮喪。有時候,它可以通過重新編譯存儲過程來解決,有時你甚至可以用重複的變量的存儲過程中是這樣的:

alter procedure p_myproc (@p1 int) as 
declare @p1_copy int; 
set @p1_copy = @p1; 

然後在查詢中使用@ p1_copy。似乎荒謬,但它的作品。

檢查我最近的問題上的同一主題:

Why does the SqlServer optimizer get so confused with parameters?

+1

謝謝老兄,那個竅門 很可笑的快速答案! – 2009-01-07 18:01:44

-1

是 - 我已經看到了這對Oracle數據庫11g作爲以及 - 相同的查詢SQL時迅速跑快於數據庫服務器的2個節點但是當從包中調用時,它就會掛起來!

必須清除共享池以獲得相同的行爲:原因某些作業/腳本正在運行,而舊版本的副本被鎖定在庫緩存/內存中,而且該執行計劃的執行計劃較差。