2012-05-18 56 views
6

我需要使用相同的查詢兩次,但有一個稍微不同的where子句。我在想,如果簡單地用一個值來調用相同的存儲過程是有效的,並且有一個IF ... ELSE ...語句,可以決定要比較哪些字段。Sql Server如何爲存儲過程中的邏輯流編譯執行計劃?

或者我應該做兩個存儲的特效,並調用基於邏輯在我的應用程序每一個?

雖然爲了正確理解,但我想詳細瞭解這一點。 如何爲此編譯執行計劃?每個IF ... ELSE ...中的每個代碼塊是否有一個?

還是編譯成一個大的執行計劃?

+0

會是什麼'IF ... ELSE

更多信息.. .'(或'CASE')恰好包含?在某些情況下,將條件抽象爲參數可能更有效。每個proc都有一個執行計劃,因此條件邏輯可能會導致性能不均衡。 –

回答

1

它使用傳遞到過程的參數的初始值編譯一次。雖然有些語句可能會受到延遲編譯的影響,但在這種情況下,它們將在最終編譯時隨參數值進行編譯。

您可以從運行的下方,並着眼於實際的執行計劃看到這一點。

CREATE TABLE T 
    (
    C INT 
) 

INSERT INTO T 
SELECT 1 AS C 
UNION ALL 
SELECT TOP (1000) 2 
FROM master..spt_values 
UNION ALL 
SELECT TOP (1000) 3 
FROM master..spt_values 

GO 

CREATE PROC P @C INT 
AS 
    IF @C = 1 
     BEGIN 
      SELECT '1' 
      FROM T 
      WHERE C = @C 
     END 
    ELSE IF @C = 2 
     BEGIN 
      SELECT '2' 
      FROM T 
      WHERE C = @C 
     END 
    ELSE IF @C = 3 
     BEGIN 
      CREATE TABLE #T 
      (
       X INT 
      ) 

      INSERT INTO #T 
      VALUES  (1) 

      SELECT '3' 
      FROM T, 
       #T 
      WHERE C = @C 
     END 

GO 

EXEC P 1 

EXEC P 2 

EXEC P 3 

DROP PROC P 

DROP TABLE T 

運行2情況下示出了從作爲T1未來1000行的估計數,因爲該聲明是根據在1傳遞的初始參數值編譯。運行3案例給出的準確估計數爲1000,因爲對臨時表(即將創建)的引用意味着該語句受到延遲編譯的影響。

3

您有權關注正在緩存的執行計劃。

馬丁給出了一個很好的例子顯示,該計劃被緩存,併爲您的邏輯是第一次執行的某個分支將得到優化。 第一次執行完該計劃後,即使您使用不同的參數調用存儲過程(sproc),導致您的執行流程選擇另一個分支,該計劃也會被重用。 這非常糟糕,會導致性能下降。我已經多次看到這種情況,需要一段時間才能找到根本原因。

這個背後的原因被稱爲「參數嗅探」,它是非常值得研究。

一個共同提出的解決方案(一說,我不諮詢)是你的存儲過程分成幾個微小的。 如果你在一個sproc內部調用一個sproc,那麼內部sproc會得到一個針對傳遞給它的參數進行優化的執行計劃。

分裂一個存儲過程成幾個小的時候沒有很好的理由(一個很好的理由將是模塊化)是一個醜陋的解決方法。 Martin表示可以通過引入對模式的更改來重新編譯語句。 我會在聲明結尾使用OPTION(RECOMPILE)。這指示優化器在考慮當前值全部變量的情況下進行語句重新編譯:不僅參數而且局部變量也被考慮在內,這可以導致好的和壞的計劃之間的差異。

回來你構建一個查詢與不同的地方根據參數條款的問題。我會用以下模式:

WHERE 
(@parameter1 is null or col1 = @parameter1 ) 
AND 
(@parameter2 is null or col2 = @parameter2 ) 
... 
OPTION (RECOMPILE) 

的一面是,該語句的執行計劃不會被緩存(不影響雖然緩存到語句的點),它可以有如果衝擊由於現在應該考慮編譯時間,因此多次執行sproc。使用生產質量數據進行測試會給你答案,如果這是一個問題或不。

好處在於,您可以編寫可讀且優雅的sprocs,而不是將優化器設置在錯誤的腳上。

另一個需要記住的選擇是,您可以禁用執行計劃緩存在精度較低的精靈級別(而不是語句級別)級別,更重要的是,不會考慮局部變量的值優化時。在 http://www.sommarskog.se/dyn-search-2005.html http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/

+0

爲什麼沒有upvotes?一個合法的答案。 –