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
  • 首先识别代码。理解起来是一团糟。
  • 临时表太多。加载 temp、加载 temp1、加载 temp2 时使用 temp1 的副本,而不是加载 temp2 时多行几行 temp1。您需要找到一种连接这些表的方法。
  • 还有一个大bug。如果@AutoRenewalChk 为 2,则不会创建 temp 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)块已被查询中的两行替换:与 cte 的左连接,以及插入语句的最后一行。
  6. @FilterCriteria 检查已被压缩并包含在最终的 select 语句中。根据您的代码,如果 @FilterCriteria 为 0,则返回所有行。否则,返回 IsRenewed = 1 和 @FilterCriteria = 1 或 IsRenewed = 0 和 @FilterCriteria = 2 的行。

事实上,由于我们在这里所做的只是将数据插入表中然后选择它,因此我们可以将其进一步压缩为单个 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 回答