2012-05-02 15 views
0

私はストアドプロシージャを使用しても問題ありませんが、多くの一時テーブルを使用するためパフォーマンスが低下します。それは改善するために/(性能向上のためのCTEまたは何か他の方法を使用している可能性がある)、それを書き換えることが可能ですこのストアドプロシージャを改善することは可能ですか?

CREATE PROCEDURE [dbo].[PORT_GetFutureOpportunities] 
    -- Add the parameters for the stored procedure here 
    (
     @SiebelAccId VARCHAR(50), 
     @FromDate DATETIME, 
     @ToDate DATETIME, 
     @FilterCriteria INT, 
     @AutoRenewalChk INT 
    ) 
AS 
BEGIN 

     DECLARE @FDate DATETIME, @TDate DATETIME 
     SET @FDate = DATEADD(day, DATEDIFF(day, 0, @FromDate), 0) 
     SET @TDate = DATEADD(day, DATEDIFF(day, 0, @ToDate), 0) 


     SELECT DISTINCT e.nai_grant_number 
     INTO #temp 
     FROM smbecommerce..SalesItem si 
     INNER JOIN smbecommerce..sales s ON s.sales_id = si.sales_id 
     INNER JOIN siebelextract..entitlement e ON SUBSTRING(e.nai_grant_number, 1, NULLIF(CHARINDEX('-', e.nai_grant_number) - 1, -1)) = CAST (s.sales_order_id AS VARCHAR)   
     WHERE si.auto_renewal_flag = (CASE WHEN @AutoRenewalChk = 1 THEN 1 END) 
     OR si.auto_renewal_flag <= (CASE WHEN @AutoRenewalChk = 0 THEN 1 END) 

      --Creating Main query 
      SELECT 
      e.nai_agreement_account_name AS [CompanyName] 
      ,c.first_name + ' ' + c.last_name AS [ContactName] 
      ,c.work_phone AS [ContactPhone] 
      ,c.email_address AS [EmailAddress] 
      ,e.entitlement_end_date AS [ExpirationDate] 
      ,e.nai_grant_number AS [GrantNumber] 
      ,e.nai_quantity AS [Quantity] 
      ,e.product_name AS [SkuDescription]    
      ,(CASE WHEN LEN(e.nai_superceded_id) > 0 THEN 1 ELSE 0 END) AS [IsRenewed] 

      INTO #temp1     
      FROM siebelextract..entitlement e  
      INNER JOIN siebelextract..account a ON a.row_id = e.nai_reseller_id   
      INNER JOIN SiebelExtract.[dbo].contact c WITH (NOLOCK) ON e.nai_primary_contact_id = c.row_id 
      WHERE a.parent_account_id = @SiebelAccId 
      AND LEN(E.nai_reason_code) = 0 
      AND EXISTS (SELECT 1 FROM smbecommerce..renewalskus rs WHERE RS.sku = E.product_name) 
      AND e.entitlement_end_date 
      BETWEEN @FDate   
      AND @TDate 

      IF (@AutoRenewalChk = 0 OR @AutoRenewalChk = 1) 
      BEGIN 
        CREATE TABLE #temp2(
             CompanyName VARCHAR(200) 
             ,ContactName VARCHAR(200) 
             ,ContactPhone VARCHAR(200) 
             ,EmailAddress VARCHAR(200) 
             ,ExpirationDate DATETIME 
             ,GrantNumber VARCHAR(200) 
             ,Quantity INT 
             ,SkuDescription VARCHAR(200) 
             ,IsRenewed INT 
            ) 
       IF @AutoRenewalChk = 0 
       BEGIN 
       INSERT INTO #temp2 select #temp1.* FROM #temp1  
       END 
       IF @AutoRenewalChk = 1 
       BEGIN  
       INSERT INTO #temp2 SELECT * FROM #temp1 WHERE #temp1.[GrantNumber] NOT IN(SELECT t1.nai_grant_number FROM #temp t1)  
       END      
       END  

       IF @FilterCriteria = 0 
       BEGIN 
        SELECT te.[CompanyName],te.[ContactName],te.[EmailAddress],te.[ContactPhone],te.[SkuDescription],te.[Quantity],te.[GrantNumber],te.[ExpirationDate],te.[IsRenewed] FROM #temp2 te  
       END 

       IF @FilterCriteria = 1 
       BEGIN 
        SELECT te.[CompanyName],te.[ContactName],te.[EmailAddress],te.[ContactPhone],te.[SkuDescription],te.[Quantity],te.[GrantNumber],te.[ExpirationDate],te.[IsRenewed] FROM #temp2 te 
        WHERE te.[IsRenewed] > 0 
       END   

       IF @FilterCriteria = 2 
       BEGIN 
        SELECT te.[CompanyName],te.[ContactName],te.[EmailAddress],te.[ContactPhone],te.[SkuDescription],te.[Quantity],te.[GrantNumber],te.[ExpirationDate],te.[IsRenewed] FROM #temp2 te 
        WHERE te.[IsRenewed] = 0 
       END 
       DROP TABLE #temp2 
       DROP TABLE #temp1 
       DROP TABLE #temp 

END 

GO 

おかげ

+6

これを行うにはどうすればいいですか? – Lucero

+0

'@ AutoRenewalChk'が0または1でなければもっと早く終了できます。'@ AutoRenewalChk'と' @FilterCriteria'の値を 'IF'ツリーでチェックし、正しいものを実行するために単一の' SELECT'を実行するように、構造を変更する傾向があります。 – HABO

答えて

1

where句にCASEを追加しますストアドプロシージャを圧縮します。もちろん、私はあなたのデータベースを持っていないので、私のSSMSは血の川のように見えますが、あなたが提供したコードに基づいて、これはうまくいくはずです。どちらかの方法を見て、私に知らせてください。

コードを貼り付けてから、自分が行ったことを説明します。

CREATE PROCEDURE dbo.PORT_GetFutureOpportunities (
    @SiebelAccId VARCHAR(50), 
    @FromDate DATETIME, 
    @ToDate DATETIME, 
    @FilterCriteria INT, 
    @AutoRenewalChk INT 
) 
AS 
BEGIN 
    DECLARE @FDate DATETIME, @TDate DATETIME 
    SET @FDate = CAST(@FromDate AS DATE) 
    SET @TDate = CAST(@ToDate AS DATE) 

    CREATE TABLE #temp(
     CompanyName VARCHAR(200), 
     ContactName VARCHAR(200), 
     ContactPhone VARCHAR(200), 
     EmailAddress VARCHAR(200), 
     ExpirationDate DATETIME, 
     GrantNumber VARCHAR(200), 
     Quantity INT, 
     SkuDescription VARCHAR(200), 
     IsRenewed INT 
    ) 

    WITH cte AS (SELECT DISTINCT e.nai_grant_number FROM smbecommerce..SalesItem si 
      INNER JOIN smbecommerce..sales s ON s.sales_id = si.sales_id 
      INNER JOIN siebelextract..entitlement e ON SUBSTRING(e.nai_grant_number, 1, NULLIF(CHARINDEX('-', e.nai_grant_number) - 1, -1)) = CAST (s.sales_order_id AS VARCHAR)   
     WHERE si.auto_renewal_flag = (CASE WHEN @AutoRenewalChk = 1 THEN 1 END) 
      OR si.auto_renewal_flag <= (CASE WHEN @AutoRenewalChk = 0 THEN 1 END)), 
     rs AS (SELECT DISTINCT sku FROM smbecommerce..renewalskus) 
    INSERT INTO #temp 
    SELECT e.nai_agreement_account_name, c.first_name + ' ' + c.last_name, c.work_phone, c.email_address, e.entitlement_end_date, 
     e.nai_grant_number, e.nai_quantity, e.product_name, (CASE WHEN LEN(e.nai_superceded_id) > 0 THEN 1 ELSE 0 END) 
    FROM siebelextract..entitlement e  
     INNER JOIN siebelextract..account a ON a.row_id = e.nai_reseller_id   
     INNER JOIN SiebelExtract.dbo.contact c WITH (NOLOCK) ON e.nai_primary_contact_id = c.row_id 
     INNER JOIN rs ON rs.sku = e.product_name 
     LEFT JOIN cte ON e.nai_grant_number = cte.nai_grant_number 
    WHERE a.parent_account_id = @SiebelAccId 
    AND LEN(E.nai_reason_code) = 0 
    AND e.entitlement_end_date BETWEEN @FDate AND @TDate 
    AND (@AutoRenewalChk = 0 OR cte.nai_grant_number IS NOT NULL) 

    SELECT CompanyName, ContactName, EmailAddress, ContactPhone, SkuDescription, Quantity, GrantNumber, ExpirationDate, IsRenewed 
    FROM #temp 
    WHERE (@FilterCriteria = 0) 
    OR IsRenewed = (1 - (@FilterCriteria -1)) 

    DROP TABLE #temp 
END 
  1. あなたはSQL2008を使用しているので、あなたはDATE型を使用することができるという利点を持っています。 DATEへのキャストは、DATEADD(DATEDIFF)アプローチ(私が好きだった、時間を取り除く新しい方法)よりもあなたの意図を少しはっきりさせます。
  2. #Temp2定義を先頭に移動し、#Tempに変更しました。このプロシージャは、複数の一時表を必要としません。
  3. 元の#Tempを単一列のCTE(cteという名前)に変更しました。また、あなたのスキュー・テーブルからパフォーマンスを犠牲にするサブ・セレクトもあるので、これもrsという名前に変更されました。
  4. #Tempに挿入するSELECT INTO#temp1を変更しました。 rs共通テーブル式への内部結合は、前と同じ方法で結果をフィルタリングしますが、これははるかに高速です。
  5. IF (@AutoRenewalChk = 0 OR @AutoRenewalChk = 1)ブロック全体が2つの行に置き換えられました。左側の結合はcteで、最後の行はinsert文です。
  6. @FilterCriteriaチェックは圧縮されており、最終的なselectステートメントに含まれています。コードに従って、@ FiltersCriteriaが0の場合、すべての行が返されます。そうでなければ、行は= 1 IsRenewedどこ戻り、@FilterCriteria = 1、または私たちがここでやっているすべてのテーブルにデータを挿入して、選択されているので、実際には= 0と@FilterCriteria = 2

をIsRenewedています

CREATE PROCEDURE dbo.PORT_GetFutureOpportunities (
    @SiebelAccId VARCHAR(50), 
    @FromDate DATETIME, 
    @ToDate DATETIME, 
    @FilterCriteria INT, 
    @AutoRenewalChk INT 
) 
AS 
BEGIN 
    DECLARE @FDate DATETIME, @TDate DATETIME 
    SET @FDate = CAST(@FromDate AS DATE) 
    SET @TDate = CAST(@ToDate AS DATE) 

    WITH cte AS (SELECT DISTINCT e.nai_grant_number FROM smbecommerce..SalesItem si 
      INNER JOIN smbecommerce..sales s ON s.sales_id = si.sales_id 
      INNER JOIN siebelextract..entitlement e ON SUBSTRING(e.nai_grant_number, 1, NULLIF(CHARINDEX('-', e.nai_grant_number) - 1, -1)) = CAST (s.sales_order_id AS VARCHAR)   
     WHERE si.auto_renewal_flag = (CASE WHEN @AutoRenewalChk = 1 THEN 1 END) 
      OR si.auto_renewal_flag <= (CASE WHEN @AutoRenewalChk = 0 THEN 1 END)), 
     rs AS (SELECT DISTINCT sku FROM smbecommerce..renewalskus) 
    SELECT e.nai_agreement_account_name AS [CompanyName], c.first_name + ' ' + c.last_name AS [ContactName], 
     c.work_phone AS [ContactPhone], c.email_address AS [EmailAddress], e.entitlement_end_date AS [ExpirationDate], 
     e.nai_grant_number AS [GrantNumber], e.nai_quantity AS [Quantity], e.product_name AS [SkuDescription], 
     (CASE WHEN LEN(e.nai_superceded_id) > 0 THEN 1 ELSE 0 END) AS [IsRenewed] 
    FROM siebelextract..entitlement e  
     INNER JOIN siebelextract..account a ON a.row_id = e.nai_reseller_id   
     INNER JOIN SiebelExtract.dbo.contact c WITH (NOLOCK) ON e.nai_primary_contact_id = c.row_id 
     INNER JOIN rs ON rs.sku = e.product_name 
     LEFT JOIN cte ON e.nai_grant_number = cte.nai_grant_number 
    WHERE a.parent_account_id = @SiebelAccId 
    AND LEN(E.nai_reason_code) = 0 
    AND e.entitlement_end_date BETWEEN @FDate AND @TDate 
    AND (@AutoRenewalChk = 0 OR cte.nai_grant_number IS NOT NULL) 
    AND ((@FilterCriteria = 0) OR CASE WHEN LEN(e.nai_superceded_id) > 0 THEN 1 ELSE 0 END = (1 - (@FilterCriteria -1))) 
END 
+0

ありがとうピーター..はい私はあなたのSPが100%の結果を出していないことを認めますが(それは明白でしたが)、純粋なセットベースのアプローチで私が解決できるいくつかのアイデアを確かに出しました。私は私の答えを更新します。しかし、とにかく私を導くことに感謝します –

1
  • すべての最初のコードをidentを。それは理解するために混乱。
  • 一時テーブルが多すぎます。 temp1をロードし、temp1をロードし、のtemp1のコピーをtemp2の負荷よりも少なくして、temp2をロードします。これらのテーブルを結合するには、 が必要です。
  • また、大きなバグがあります。 @AutoRenewalChkが2の場合、temp 2は作成されません。 が作成されますが、クエリによってアクセスされます。それは失敗するでしょう。
  • 最後に、これは何のパフォーマンスが向上しないかもしれませんが、代わりに @FilterCriteriaの各可能性のためにIFを有するので、クリーンな コードを生成します、クエリを実行し、私が持っている
関連する問題