如何在sql存储过程中优化重复存在和非存在子句?

时间:2016-06-21 20:00:10

标签: sql sql-server-2012

我有一个存储过程,我重复了相同的'not exists'子句。每个选择中的每个“不存在”子句在随后的选择查询中重复,并且“exists”子句在后续选择查询中变为“不存在”。 有没有办法我可以只做一次“非存在”和“存在”并保存这些结果并在整个过程中使用它们?优化的方法是什么? 谢谢!

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[sp_GetCaseType] 
@ID numeric(18,0)
AS

BEGIN                   
SET NOCOUNT ON;    
DECLARE @cnt int;

SELECT @cnt = COUNT(*) 
            FROM tblCase c WITH (NOLOCK) 
            join tblDepartment cd WITH (NOLOCK)  on cd.DepartmentID = c.DepartmentID
            join tblType ct WITH (NOLOCK)  on ct.TypeID = cd.TypeID
            WHERE ct.Type in ('AG', 'PH')
            and 
            not exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                        join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                        WHERE ca.Code in ('Z', 'W')
                        and ch.ID = @ID)
            and
            c.ID = @ID

IF (@cnt > 1)
    RETURN 'CATEGORY 1'

SELECT @cnt = COUNT(*) 
            FROM tblCase c WITH (NOLOCK) 
            join tblDepartment cd WITH (NOLOCK)  on cd.DepartmentID = c.DepartmentID
            join tblType ct WITH (NOLOCK)  on ct.TypeID = cd.TypeID
            WHERE ct.Type in ('AG', 'PH')
            and 
            not exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                        join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                        WHERE ca.Code in ('Z', 'W')
                        and ch.ID = @ID)
            and
            exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                    join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                    WHERE ca.Code in ('N', 'O')
                    and ch.ID = @ID)
            and
            c.ID = @ID

IF (@cnt > 1)
    RETURN 'CATEGORY 2'

SELECT @cnt = COUNT(*) 
        FROM tblCase c WITH (NOLOCK) 
        join tblDepartment cd WITH (NOLOCK)  on cd.DepartmentID = c.DepartmentID
        join tblType ct WITH (NOLOCK)  on ct.TypeID = cd.TypeID
        WHERE ct.Type in ('AG', 'PH')
        and 
        not exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                    join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                    WHERE ca.Code in ('Z', 'W')
                    and ch.ID = @ID)
        and
        not exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                WHERE ca.Code in ('N', 'O')
                and ch.ID = @ID)
        and
        exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                WHERE ca.Code in ('D', 'B')
                and ch.ID = @ID)
        and
        c.ID = @ID

IF (@cnt > 1)
    RETURN 'CATEGORY 2'


SELECT @cnt = COUNT(*) 
        FROM tblCase c WITH (NOLOCK) 
        join tblDepartment cd WITH (NOLOCK)  on cd.DepartmentID = c.DepartmentID
        join tblType ct WITH (NOLOCK)  on ct.TypeID = cd.TypeID
        WHERE ct.Type in ('AG', 'PH')
        and 
        not exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                    join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                    WHERE ca.Code in ('Z', 'W')
                    and ch.ID = @ID)
        and
        not exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                WHERE ca.Code in ('N', 'O')
                and ch.ID = @ID)
        and
        not exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                WHERE ca.Code in ('D', 'B')
                and ch.ID = @ID)
        and
        exists (SELECT * FROM tblCharge ch WITH (NOLOCK)
                join tblAction ca WITH (NOLOCK) on ch.ActionID = ca.ActionID
                WHERE ca.Code in ('A', 'C')
                and ch.ID = @ID)
        and
        c.ID = @ID

IF (@cnt > 1)
    RETURN 'CATEGORY 2'

END

2 个答案:

答案 0 :(得分:1)

如果它们是相同的并且它们不是相关的子查询,那么您可以在存储过程开始时将结果保存在变量中,然后在其余查询中使用该变量:

DECLARE
    @zw_exists    BIT = 0

IF EXISTS (SELECT * FROM ... WHERE Code IN ('Z', 'W') AND CH.ID = @ID)
    @zw_exists = 1

对每种类型的查询执行相同操作,然后在其他查询中使用该变量。

答案 1 :(得分:1)

尝试将exists和non存在结合到一个查询中,并且只返回top 1。这样,您可以最小化SELECT子句中每WHERE个语句返回的行数。还为您的proc添加了SET NOCOUNT ON;,这是一种快速简便的方法,可以提升性能:

SET ANSI_NULLS ON;
GO

SET QUOTED_IDENTIFIER ON;
GO

ALTER PROCEDURE [dbo].[sp_GetCaseType] @ID NUMERIC(18, 0)
AS
    SET NOCOUNT ON; 
    BEGIN
        SET NOCOUNT ON;
        DECLARE @cnt INT;
        SELECT @cnt = COUNT(*)
        FROM   tblCase c WITH (NOLOCK)
             JOIN tblDepartment cd WITH (NOLOCK) ON cd.DepartmentID = c.DepartmentID
             JOIN tblType ct WITH (NOLOCK) ON ct.TypeID = cd.TypeID
        WHERE  ct.Type IN('AG', 'PH')
             AND NOT EXISTS
                        (SELECT *
                         FROM   tblCharge ch WITH (NOLOCK)
                               JOIN tblAction ca WITH (NOLOCK) ON ch.ActionID = ca.ActionID
                         WHERE  ca.Code IN('Z', 'W')
                               AND ch.ID = @ID)
                         AND c.ID = @ID;
        IF(@cnt > 1)
           RETURN 'CATEGORY 1';
        SELECT @cnt = COUNT(*)
        FROM   tblCase c WITH (NOLOCK)
             JOIN tblDepartment cd WITH (NOLOCK) ON cd.DepartmentID = c.DepartmentID
             JOIN tblType ct WITH (NOLOCK) ON ct.TypeID = cd.TypeID
        WHERE  ct.Type IN('AG', 'PH')
             AND EXISTS
                     (SELECT TOP 1 1
                      FROM         tblCharge ch WITH (NOLOCK)
                                JOIN tblAction ca WITH (NOLOCK) ON ch.ActionID = ca.ActionID
                      WHERE        ca.Code NOT IN('Z', 'W')
                                AND ca.Code IN('N', 'O')
                                AND ch.ID = @ID)
                      AND c.ID = @ID;
        IF(@cnt > 1)
           RETURN 'CATEGORY 2';
        SELECT @cnt = COUNT(*)
        FROM   tblCase c WITH (NOLOCK)
             JOIN tblDepartment cd WITH (NOLOCK) ON cd.DepartmentID = c.DepartmentID
             JOIN tblType ct WITH (NOLOCK) ON ct.TypeID = cd.TypeID
        WHERE  ct.Type IN('AG', 'PH')
             AND EXISTS
                     (SELECT TOP 1 1
                      FROM         tblCharge ch WITH (NOLOCK)
                                JOIN tblAction ca WITH (NOLOCK) ON ch.ActionID = ca.ActionID
                      WHERE        ca.Code NOT IN('Z', 'W', 'N', 'O')
                                AND ca.Code IN('D', 'B')
                                AND ch.ID = @ID)
                      AND c.ID = @ID;
        IF(@cnt > 1)
           RETURN 'CATEGORY 2';
        SELECT @cnt = COUNT(*)
        FROM   tblCase c WITH (NOLOCK)
             JOIN tblDepartment cd WITH (NOLOCK) ON cd.DepartmentID = c.DepartmentID
             JOIN tblType ct WITH (NOLOCK) ON ct.TypeID = cd.TypeID
        WHERE  ct.Type IN('AG', 'PH')
             AND EXISTS
                     (SELECT TOP 1 1
                      FROM         tblCharge ch WITH (NOLOCK)
                                JOIN tblAction ca WITH (NOLOCK) ON ch.ActionID = ca.ActionID
                      WHERE        ca.Code NOT IN('Z', 'W', 'N', 'O', 'D', 'B')
                                AND ca.Code IN('A', 'C')
                                AND ch.ID = @ID)
                      AND c.ID = @ID;
        IF(@cnt > 1)
           RETURN 'CATEGORY 2';
    END;