1

您好我有一個存儲過程SQL Server 2008的存儲過程的性能問題

 ALTER PROCEDURE [dbo].[usp_EP_GetTherapeuticalALternates] 
    (
     @NDCNumber CHAR(11) , 
     @patientid INT , 
     @pbmid INT 
    ) 
AS 
    BEGIN 
     TRUNCATE TABLE TempTherapeuticAlt 
     INSERT INTO TempTherapeuticAlt 
       SELECT --PR.ProductID AS MedicationID , 
         NULL AS MedicationID , 
         PR.ePrescribingName AS MedicationName , 
         U.Strength AS MedicationStrength , 
         FRM.FormName AS MedicationForm , 
         PR.DEAClassificationID AS DEASchedule , 
         NULL AS NDCNumber 
     --INTO #myTemp 
       FROM DatabaseTwo.dbo.Product PR 
         JOIN (SELECT MP.MarketedProductID 
           FROM  DatabaseTwo.dbo.Therapeutic_Concept_Tree_Specific_Product TCTSP 
             JOIN DatabaseTwo.dbo.Marketed_Product MP ON MP.SpecificProductID = TCTSP.SpecificProductID 
             JOIN (SELECT TCTSP.TherapeuticConceptTreeID 
               FROM  DatabaseTwo.dbo.Marketed_Product MP 
                 JOIN DatabaseTwo.dbo.Therapeutic_Concept_Tree_Specific_Product TCTSP ON MP.SpecificProductID = TCTSP.SpecificProductID 
                 JOIN (SELECT 
                   PR.MarketedProductID 
                   FROM 
                   DatabaseTwo.dbo.Package PA 
                   JOIN DatabaseTwo.dbo.Product PR ON PA.ProductID = PR.ProductID 
                   WHERE 
                   PA.NDC11 = @NDCNumber 
                  ) PAPA ON MP.MarketedProductID = PAPA.MarketedProductID 
              ) xxx ON TCTSP.TherapeuticConceptTreeID = xxx.TherapeuticConceptTreeID 
          ) MPI ON PR.MarketedProductID = MPI.MarketedProductID 
         JOIN (SELECT P.ProductID , 
             O.Strength , 
             O.Unit 
           FROM  DatabaseTwo.dbo.Product AS P 
             INNER JOIN DatabaseTwo.dbo.Marketed_Product 
             AS M ON P.MarketedProductID = M.MarketedProductID 
             INNER JOIN DatabaseTwo.dbo.Specific_Product 
             AS S ON M.SpecificProductID = S.SpecificProductID 
             LEFT OUTER JOIN DatabaseTwo.dbo.OrderableName_Combined 
             AS O ON S.SpecificProductID = O.SpecificProductID 
           GROUP BY P.ProductID , 
             O.Strength , 
             O.Unit 
          ) U ON PR.ProductID = U.ProductID 
         JOIN (SELECT PA.ProductID , 
             S.ScriptFormID , 
             F.Code AS NCPDPScriptFormCode , 
             S.FormName 
           FROM  DatabaseTwo.dbo.Package AS PA 
             INNER JOIN DatabaseTwo.dbo.Script_Form 
             AS S ON PA.NCPDPScriptFormCode = S.NCPDPScriptFormCode 
             INNER JOIN DatabaseTwo.dbo.FormCode AS F ON S.FormName = F.FormName 
           GROUP BY PA.ProductID , 
             S.ScriptFormID , 
             F.Code , 
             S.FormName 
          ) FRM ON PR.ProductID = FRM.ProductID 
          WHERE 
          (PR.OffMarketDate IS NULL) 
     OR (PR.OffMarketDate = '') 
     OR (PR.OffMarketDate = '1899-12-30 00:00:00.000') 
     OR (PR.OffMarketDate <> '1899-12-30 00:00:00.000' 
      AND DATEDIFF(dd, GETDATE(),PR.OffMarketDate) > 0 
      ) 
       GROUP BY PR.ePrescribingName , 
         U.Strength , 
         FRM.FormName , 
         PR.DEAClassificationID 
       -- ORDER BY pr.ePrescribingName 

     SELECT LL.ProductID AS MedicationID , 
       temp.MedicationName , 
       temp.MedicationStrength , 
       temp.MedicationForm , 
       temp.DEASchedule , 
       temp.NDCNumber , 
       fs.[ReturnFormulary] AS FormularyStatus , 
       copay.CopaTier , 
       copay.FirstCopayTerm , 
       copay.FlatCopayAmount , 
       copay.PercentageCopay , 
       copay.PharmacyType, 
       dbo.udf_EP_GetBrandGeneric(LL.ProductID) AS BrandGeneric 
     FROM TempTherapeuticAlt temp 
       OUTER APPLY (SELECT TOP 1 
             ProductID 
           FROM  DatabaseTwo.dbo.Product 
           WHERE  ePrescribingName = temp.MedicationName 
          ) AS LL 
       OUTER APPLY [dbo].[udf_EP_tbfGetFormularyStatus](@patientid, 
                   LL.ProductID, 
                   @pbmid) AS fs 
       OUTER APPLY (SELECT TOP 1 
             * 
           FROM  udf_EP_CopayDetails(LL.ProductID, 
                  @PBMID, 
                  fs.ReturnFormulary) 
          ) copay 
     --ORDER BY LL.ProductID 
     TRUNCATE TABLE TempTherapeuticAlt 
    END 

在我的開發服務器我在每個表

有63K數據,因此這個過程花費了大約30秒返回結果。

在我的生產服務器上,它超時或花費1分鐘以上。 我想知道我的生產服務器表充滿了1400萬條記錄,

這是否是一個原因。

如果是這樣,我可以做什麼,我有所有表上的索引。

任何幫助將不勝感激。

感謝

執行計劃 http://www.sendspace.com/file/hk8fao

重大泄漏

OUTER APPLY [dbo].[udf_EP_tbfGetFormularyStatus](@patientid, 
                   LL.ProductID, 
                   @pbmid) AS fs 

回答

4

一些策略,可以幫助:

  1. BY語句刪除第一個訂單,那些殺手的複雜的查詢不應該b必要的。

  2. 使用CTE將查詢分解爲可以單獨尋址的小塊。

  3. 減少嵌套在第一組的JOIN的

  4. 提取第二和第三組的連接(分組的)和連接和分組一切之前插入那些到臨時索引表。

  5. 您沒有包括function1function2的定義 - 自定義函數通常是隱藏性能問題的地方。

沒有看到執行計劃,這是很難看到的特殊問題而定。

+0

我添加了執行計劃的下載鏈接,可能會有所幫助 – HaBo

+0

我發現問題在於調用函數,tbfGetFOrmularyStatus()不確定這是否是調用udf的最佳方式 – HaBo

3

您有一個查詢可以從4個或5個表格中選擇數據,其中有些會多次顯示。如果沒有深入分析你想要實現什麼以及實際是什麼表結構,真的很難說。

數據大小絕對是一個問題;我認爲很明顯,需要處理的數據越多,查詢所需的時間越長。一些一般性建議...直接運行查詢並檢查執行計劃。它可能會揭示瓶頸。然後檢查統計信息是否是最新的。此外,請查看您的表格,在某些情況下,分區可能會有所幫助。此外,您可以嘗試更改表格並創建聚集索引(而不是PK)(因爲它是默認完成的,除非另有說明),但是在其他列上,因此您的查詢將受益於特定的記錄物理順序。注意:只有當你確定你在做什麼時才做。

最後,嘗試重構您的查詢。我有一種感覺,有一種更好的方法來獲得所需的結果(對不起,沒有理解表結構和預期結果,我不能說出確切的解決方案,但同一表和一堆派生表的多個連接對我來說並不好)