我有一個存儲過程,性能可怕。當我聲明一個變量時,設置它的值,然後在where子句中使用它,該語句需要花費一個小時才能運行。當我在where子句中硬編碼變量時,它在不到一秒的時間內運行。參數的性能不如硬編碼值
我開始通過執行計劃瞭解它有什麼問題。它看起來像當我嘗試傳遞一些聲明的變量時,執行計劃包含一些哈希匹配,因爲它從使用UNION和公用表表達式的視圖中選擇值。
/************* Begin of Stored Procedure ***************/ CREATE PROCEDURE GetFruit @ColorId bigint, @SeasionId bigint WITH RECOMPILE AS BEGIN SELECT A.Name FROM [Apple_View] A /* This is the view down below */ INNER JOIN [Fruit] F ON (F.ColorId = @ColorId AND A.FruitId = F.FruitId) WHERE (A.ColorId = @ColorId AND A.SeasonId = @SeasonId) END /************* End of Stored Procedure ***************/ /************* Begin of View ***************/ WITH Fruits (FruitId, ColorId, SeasonId) AS ( -- Anchor member SELECT F.FruitId ,F.ColorId ,F.SeasonId FROM (( SELECT DISTINCT EF.FruitId ,EF.ColorId ,EF.SeasonId ,EF.ParentFruitId FROM ExoticFruit EF INNER JOIN Fruit FR ON FR.FruitId = EF.FruitId UNION SELECT DISTINCT SF.FruitId ,SF.ColorId ,SF.SeasonId ,SF.ParentFruitId FROM StinkyFruit SF INNER JOIN Fruit FR ON FR.FruitId = SF.FruitId UNION SELECT DISTINCT CF.FruitId ,CF.ColorId ,CF.SeasonId ,CF.ParentFruitId FROM CrazyFruit CF INNER JOIN Fruit FR ON FR.FruitId = CF.FruitId )) f UNION ALL -- Recursive Parent Fruit SELECT FS.FruitId ,FS.ColorId ,FS.SeasonId ,FS.ParentFruitId FROM Fruits FS INNER JOIN MasterFruit MF ON MF.[ParentFruitId] = fs.[FruitId] ) SELECT DISTINCT FS.FruitId ,FS.ColorId ,FS.SeasonId FROM Fruits FS /************* End of View ***************/ /* To Execute */ EXEC GetFruit 1,3
如果我使用它需要一個多小時,這裏的設定值運行存儲過程的執行計劃。
如果我運行存儲過程移除聲明和設定值,只是設置Where子句中它在不到一秒鐘的運行,這裏下面的語句是執行計劃:
WHERE(A.ColorId = 1 AND A.SeasonId = 3)
請注意硬編碼變量在第一次使用散列集時如何使用索引。這是爲什麼?爲什麼where子句中的硬編碼值與聲明的變量不同?
-------這就是最後用@ user1166147 ------的幫助
我改變了存儲過程使用sp_executesql的執行。
CREATE PROCEDURE GetFruit @ColorId bigint, @SeasionId bigint WITH RECOMPILE AS BEGIN DECLARE @SelectString nvarchar(max) SET @SelectString = N'SELECT A.Name FROM [Apple_View] A /* This is the view down below */ INNER JOIN [Fruit] F ON (F.ColorId = @ColorId AND A.FruitId = F.FruitId) WHERE (A.ColorId = ' + CONVERT(NVARCHAR(MAX), @ColorId) + ' AND A.SeasonId = ' + CONVERT(NVARCHAR(MAX), @SeasonId) + ')' EXEC sp_executesql @SelectString END
你檢查,以確保您的參數的數據類型匹配列的數據類型? – HackedByChinese
這些變量不是參數。 SQL Server不會執行變量嗅探,因此選擇性估計將會是猜測。如果添加「OPTION(RECOMPILE)」? –
使用選項重新編譯。有一種叫做參數嗅探的方法,其中sql server根據輸入值生成不同的查詢計劃 – praveen