过程中的游标太长而无法运行

时间:2015-12-24 10:26:30

标签: sql-server tsql stored-procedures sql-server-2008-r2 sql-optimization

我想优化下面使用的游标的性能,或者部署一些其他方法来实现所需的结果,这比下面使用的游标快得多。目前,光标能够在5分钟内对1000个客户进行操作,这导致每月平均约250,000个客户的运行时间为1250分钟(每月)。

我正在使用Microsoft SQL Server 2008 R2进行练习。光标位于每月运行的过程中。该过程的month参数是@month_key(datetime变量),它未在下面给出的代码中声明。请记住,该过程需要运行10年的数据,下面的代码是程序运行中最耗时的部分。

--DECLARING VARIABLES 
DECLARE @EVENT_12_MONTH_FLAG DATETIME;
DECLARE @I INT;
DECLARE @CUSTOMER INT;
DECLARE @START_DATE DATETIME;
DECLARE @EVENT_FLAG INT;
DECLARE @EVENT_CURSOR CURSOR;


---CURSOR 
SET @EVENT_CURSOR = CURSOR FOR
SELECT DISTINCT CUSTOMER_NO 
FROM EVENT_DRV  
OPEN @EVENT_CURSOR;
FETCH NEXT FROM @EVENT_CURSOR INTO 
@CUSTOMER;

--EVENT FLAG
SET @EVENT_FLAG = (SELECT CASE WHEN DEF_FLAG = 1 THEN 1
WHEN (YEAR(A.MONTH_KEY) = YEAR(WRT_OFF_DTE) and MONTH(A.MONTH_KEY) = MONTH(WRT_OFF_DTE)) THEN 1 
WHEN  DATEDIFF(MONTH,A.MONTH_KEY,WRT_OFF_DTE) = 1 THEN 1  ELSE 0 END
FROM EVENT_DRV A INNER JOIN EVENT_VAR B ON A.CUSTOMER_NO = B.CUSTOMER_NO AND A.MONTH_KEY = B.MONTH_KEY
WHERE A.CUSTOMER_NO=@CUSTOMER AND A.MONTH_KEY = DATEADD(MONTH,-12,@MONTH_KEY)) 

WHILE @@FETCH_STATUS = 0
BEGIN 

SET @I =12;
WHILE (@I >=0)
BEGIN
    SET @I=@I-1 ;
    SET @START_DATE=DATEADD(MONTH,-@I, @MONTH_KEY)


    SET @EVENT_12_MONTH_FLAG = (SELECT CASE WHEN YEAR(A.MONTH_KEY) = YEAR(DEF_MONTH_1) AND MONTH(A.MONTH_KEY) = MONTH(DEF_MONTH_1) THEN 1
       WHEN (YEAR(A.MONTH_KEY) = YEAR(WRT_OFF_DTE) and MONTH(A.MONTH_KEY) = MONTH(WRT_OFF_DTE)) THEN 1 
       WHEN  DATEDIFF(MONTH,A.MONTH_KEY,WRT_OFF_DTE) = 1 THEN 1  ELSE 0 
      END  
      FROM EVENT_DRV A INNER JOIN EVENT_VAR B
        ON A.MONTH_KEY=B.MONTH_KEY AND A.CUSTOMER_NO = B.CUSTOMER_NO
      WHERE A.CUSTOMER_NO = @CUSTOMER AND A.MONTH_KEY = @START_DATE)

    IF @EVENT_FLAG = 0 AND @EVENT_12_MONTH_FLAG = 1
    BEGIN
    UPDATE  EVENT_DRV 
    SET EVENT_DRV.def_flag_final =1 
    WHERE MONTH_KEY=DATEADD(MONTH,-12,@MONTH_KEY)
    BREAK
    END
END  
FETCH NEXT FROM @EVENT_CURSOR INTO @CUSTOMER;
END
CLOSE @EVENT_CURSOR;
DEALLOCATE @EVENT_CURSOR;

1 个答案:

答案 0 :(得分:0)

DECLARE
      @EVENT_12_MONTH_FLAG DATETIME
    , @CUSTOMER INT
    , @EVENT_FLAG INT
    , @MONTH_KEY DATETIME

SELECT @EVENT_12_MONTH_FLAG =
    CASE
        WHEN 
            (YEAR(A.MONTH_KEY) = YEAR(DEF_MONTH_1) AND MONTH(A.MONTH_KEY) = MONTH(DEF_MONTH_1))
        OR 
            (YEAR(A.MONTH_KEY) = YEAR(WRT_OFF_DTE) AND MONTH(A.MONTH_KEY) = MONTH(WRT_OFF_DTE))
        OR
            DATEDIFF(MONTH,A.MONTH_KEY,WRT_OFF_DTE) = 1
        THEN 1
        ELSE 0 
    END  
FROM EVENT_DRV A
JOIN EVENT_VAR B ON A.MONTH_KEY = B.MONTH_KEY AND A.ACCOUNT_NO = B.ACCOUNT_NO
--WHERE -- !!

DECLARE cur CURSOR FAST_FORWARD READ_ONLY LOCAL FOR
    SELECT DISTINCT CUSTOMER_NO 
    FROM dbo.EVENT_DRV
    WHERE @EVENT_12_MONTH_FLAG = 1

OPEN cur

FETCH NEXT FROM cur INTO @CUSTOMER

WHILE @@FETCH_STATUS = 0 BEGIN

     SELECT @EVENT_FLAG = 
        CASE
            WHEN
                    DEF_FLAG = 1
                OR
                    DATEDIFF(MONTH, A.MONTH_KEY, WRT_OFF_DTE) = 1
                OR
                    (YEAR(A.MONTH_KEY) = YEAR(WRT_OFF_DTE) AND MONTH(A.MONTH_KEY) = MONTH(WRT_OFF_DTE))
            THEN 1
            ELSE 0
        END
    FROM dbo.EVENT_DRV A
    JOIN dbo.EVENT_VAR B ON A.MONTH_KEY = B.MONTH_KEY AND A.ACCOUNT_NO = B.ACCOUNT_NO -- !!
    WHERE A.CUSTOMER_NO = @CUSTOMER
        AND A.MONTH_KEY = DATEADD(MONTH, -12, @MONTH_KEY)

    IF @EVENT_FLAG = 0 BEGIN

        UPDATE EVENT_DRV 
        SET EVENT_DRV.def_flag_final = 1 
        WHERE MONTH_KEY = DATEADD(MONTH, -12, @MONTH_KEY)
            AND CUSTOMER_NO = @CUSTOMER -- !!

    END

    FETCH NEXT FROM cur INTO @CUSTOMER

END

CLOSE cur
DEALLOCATE cur

很难理解您的业务逻辑......无论如何检查此代码