如何添加CTE以提高存储过程的性能?

时间:2019-05-03 03:38:21

标签: sql sql-server stored-procedures common-table-expression

我有一个类似于以下内容的存储过程:

CREATE PROCEDURE [Schema].[ProcName]
    (@PhoneNum  VARCHAR(100)
     @EmailAddr VARCHAR(100)
     @DriverLic VARCHAR(100)
     @EligiblityDate VARCHAR(10))
AS
BEGIN
SET NOCOUNT ON;
    DECLARE @Phone BIT = 0,
            @Email BIT = 0,
            @License BIT = 0

    IF (SELECT Value FROM Table 
        WHERE Product = 'ProductA' 
          AND @EligibilityDate BETWEEN EligStart AND EligEnd 
          AND ProductType = 1 
          AND Value = @PhoneNum 
          AND IsActive = 1) 
        SET @Phone = 1

    IF (SELECT Value FROM Table 
        WHERE Product = 'ProductA' 
          AND @EligibilityDate BETWEEN EligStart AND EligEnd 
          AND ProductType = 2 
          AND Value = @EmailAddr 
          AND IsActive = 1) 
        SET @Email = 1

    IF (SELECT Value FROM Table 
        WHERE Product = 'ProductA' 
          AND @EligibilityDate BETWEEN EligStart AND EligEnd 
          AND ProductType = 3 
          AND Value = @DriverLic 
          AND IsActive = 1) 
        SET @License = 1

    SELECT 
        @Phone AS Phone,
        @Email AS Email,
        @License AS License;

    RETURN 0;

我希望通过使用CTE来改善此查询的性能。但是,我不确定该怎么做,因为我以前从未使用过CTE。

2 个答案:

答案 0 :(得分:2)

因此,为此,CTE对您没有好处。 CTE适用于您在一个查询中重新使用子选择,或者您要进行递归操作时,它们通常不如我们希望的那样有用。由于查询的复杂性,我担心只需要先掌握基础知识,而担心CTE会在您发现自己需要这些CTE时,而不是无缘无故地联系他们。

我认为您需要的是以下内容:

Create Procedure [Schema].[ProcName]
    (@PhoneNum   VARCHAR(100),
    @EmailAddr  VARCHAR(100),
    @DriverLic  VARCHAR(100),
    @EligiblityDate VARCHAR(10))
AS
BEGIN

    select
        max(case when ProductType = 1 and [Value] = @PhoneNum then 1 else 0 end) as PhoneNum,
        max(case when ProductType = 2 and [Value] = @EmailAddr then 1 else 0 end) as EmailAddr,
        max(case when ProductType = 3 and [Value] = @DriverLic then 1 else 0 end) as DriverLic
    from [Table]
    WHERE
        Product = 'ProductExample'
        AND @EligibilityDate BETWEEN EligStart and EligEnd
        AND IsActive = 1
END

这具有将多个查询(当您将这样的代码复制!您很可疑!)合并到一个查询中的类似效果,但是不需要子选择。

答案 1 :(得分:0)

我想你想要这个

CREATE PROCEDURE [Schema].[ProcName]
    (@PhoneNum  VARCHAR(100),
     @EmailAddr VARCHAR(100),
     @DriverLic VARCHAR(100),
     @EligiblityDate VARCHAR(10))
AS
BEGIN
SET NOCOUNT ON;
    DECLARE @Phone BIT = 0,
            @Email BIT = 0,
            @License BIT = 0

    SELECT @Phone = case when ProductType = 1 and Value = @PhoneNum then 1 else 0 end,
        @Email = case when ProductType = 2 and Value = @EmailAddr then 1 else 0 end,
        @License = case when ProductType = 3 and Value = @DriverLic then 1 else 0 end
    FROM Table 
        WHERE Product = 'ProductA' 
          AND @EligibilityDate BETWEEN EligStart AND EligEnd 
          AND ProductType = 1 

    SELECT 
        @Phone AS Phone,
        @Email AS Email,
        @License AS License;

    RETURN 0;
END