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

ありがとう

4

2 に答える 2

1
  • まず、コードを特定します。理解するのはめちゃくちゃです。
  • 一時テーブルが多すぎます。temp1の数行を追加してtemp2をロードするよりも、temp1のコピーを使用してtemp1、temp2をロードします。これらのテーブルを結合する方法を見つける必要があります。
  • また、大きなバグがあります。@AutoRenewalChkが2の場合、一時2は作成されませんが、クエリによってアクセスされます。それは失敗します。
  • 最後に、これによってパフォーマンスが向上することはありませんが、@ FilterCriteriaの可能性ごとにIFを設定する代わりに、よりクリーンなコードを生成し、クエリを実行してwhere句にCASEを追加します。
于 2012-05-02T12:51:40.930 に答える
1

ストアドプロシージャを圧縮しました。もちろん、私はあなたのデータベースを持っていないので、私の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という名前)に変更しました。skuテーブルからパフォーマンスを犠牲にするサブセレクトもあるので、これもrsという名前のcteに移動されました。
  4. SELECT INTO#temp1を#Tempに挿入するように変更しました。rs共通テーブル式への内部結合は、以前と同じ方法で結果をフィルタリングしますが、これははるかに高速になります。
  5. クエリでは、ブロック全体IF (@AutoRenewalChk = 0 OR @AutoRenewalChk = 1)が2行に置き換えられています。cteとの左結合と、挿入ステートメントの最後の行です。
  6. @FilterCriteriaチェックが圧縮され、最終的なselectステートメントに含まれています。コードに従って、@ FilterCriteriaが0の場合、すべての行が返されます。それ以外の場合は、IsRenewed=1および@FilterCriteria=1、またはIsRenewed=0および@FilterCriteria=2の行が返されます。

実際、ここで行っているのはテーブルにデータを挿入してから選択することだけなので、これをさらに1つのselectステートメントに圧縮できます。

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
于 2012-05-02T15:24:07.917 に答える