SQL Server - 提高游标速度

时间:2014-06-17 19:31:44

标签: sql sql-server-2008-r2

我使用下面的代码来检查特定行的列@act_value是否高于24.0,用光标循环遍历表的每一行。如果@act_value高于24.0,则将完成若干操作以及更新该条目并插入新条目。也就是说,查询需要超过26分钟才能运行(从下面提供此添加之前的0:16分钟开始)并且可能过于耗费资源。是否有更好的配置可以加快此操作?

DECLARE cur_hours_check CURSOR
FOR
    SELECT 
       Period, Act_Batch_Time, Kg_Per_Hour, Total_QT_Produced, 
       Total_Possible_KG,
       --The columns not affected but need for inserting the shadow day
       Division, Region, Business_Region, Plant, Work_Center, DaysInMonth, 
       Total_Possible_Hours, Demonstrated_Capacity
    FROM 
       zt_Demonstrated_Capacity_Trend

OPEN cur_hours_check

DECLARE             --Cursor Variables Pulling data
    @period                   datetime
,   @act_hours                float
,   @over_hours               float
,   @Total_QT_Produced        float
,   @KG_per_hour              float
,   @Total_Possible_KG        float
--then the extra
,   @Division                 varchar(20)
,   @Region                   varchar(20)
,   @Business_Region          varchar(20)
,   @Plant                    varchar(40)
,   @Work_Center              varchar(40)
,   @DaysInMonth              float
,   @Total_Possible_Hours     float
,   @Demonstrated_Capacity    float

DECLARE             --Cursor Shadow variables:
    @shadow_period                 datetime 
,   @shadow_act_hours              float
,   @shadow_Total_QT_Produced      float
,   @shadow_Total_Possible_KG      float
,   @shadow_Percent_of_Total_Hours float

DECLARE             --Cursor adjusted first day variables
    @adj_act_hours                 float
,   @adj_Total_QT_Produced         float
,   @adj_Total_Possible_KG         float
,   @adj_Percent_of_Total_Hours    float

FETCH FROM cur_hours_check
    INTO @period, @act_hours, @KG_per_hour, @Total_QT_Produced, @Total_Possible_KG
   ,@Division, @Region, @Business_Region, @Plant, @Work_Center, @DaysInMonth, @Total_Possible_Hours, @Demonstrated_Capacity

WHILE @@FETCH_STATUS = 0
BEGIN

    IF @act_hours > 24.0
    BEGIN
    -- Setting the shadow period to carry over values relative to 24 hour time window
        SET @shadow_period = dateadd(dd, datediff(dd, 0, @period) + 1, 0) 
        SET @shadow_act_hours = @act_hours - 24.0
        SET @shadow_Total_QT_Produced = (@Total_QT_Produced - (@KG_per_hour * @shadow_act_hours))
        SET @shadow_Percent_of_Total_Hours = (@shadow_act_hours/24.0)*100

    -- Adjusting first period for 24 hour window of operation
        SET @adj_act_hours = 24.0
        SET @adj_Total_QT_Produced =  @Total_QT_Produced - (@KG_per_hour * 24.0)
        SET @adj_Total_Possible_KG = @Total_Possible_KG *(1-( @shadow_act_hours/@act_hours ))
        SET @adj_Percent_of_Total_Hours = 100

    -- now update that record, as well as insert the shadow day
        UPDATE zt_Demonstrated_Capacity_Trend
        SET Period = @period
        , Act_Batch_Time = 24.0
        , Total_QT_Produced = @adj_Total_QT_Produced
        , Total_Possible_KG = @adj_Total_Possible_KG
        , Kg_Per_Hour = @KG_per_hour
        , Percent_of_Total_Hours = @adj_Percent_of_Total_Hours
        , Division = @Division
        , Region = @Region
        , Business_Region = @Business_Region
        , Plant = @Plant
        , Work_Center = @Work_Center
        , DaysInMonth = @DaysInMonth
        , Total_Possible_Hours = @Total_Possible_Hours
        , Demonstrated_Capacity = @Demonstrated_Capacity
        WHERE CURRENT OF cur_hours_check 

    --Inserting the shadow record
        INSERT INTO [dbo].[zt_Demonstrated_Capacity_Trend](
        [Period]
        ,[Division]
        ,[Region]
        ,[Business_Region]
        ,[Plant]
        ,[Work_Center]
        ,[Kg_Per_Hour]
        ,[Total_QT_Produced]
        ,[Act_Batch_Time]
        ,[DaysInMonth]
        ,[Total_Possible_Hours]
        ,[Demonstrated_Capacity]
        ,[Total_Possible_KG]
        ,[Percent_of_Total_Hours])
        VALUES
        (@shadow_period
        ,@Division
        ,@Region
        ,@Business_Region
        ,@Plant
        ,@Work_Center
        ,@Kg_Per_Hour
        ,@shadow_Total_QT_Produced
        ,@shadow_act_hours
        ,@DaysInMonth
        ,@Total_Possible_Hours
        ,@Demonstrated_Capacity
        ,@adj_Total_Possible_KG
        ,@shadow_Percent_of_Total_Hours)
    END
    FETCH NEXT FROM cur_hours_check
    INTO @period, @act_hours, @KG_per_hour, @Total_QT_Produced, @Total_Possible_KG
   ,@Division, @Region, @Business_Region, @Plant, @Work_Center, @DaysInMonth, @Total_Possible_Hours, @Demonstrated_Capacity

END;

CLOSE       cur_hours_check
DEALLOCATE  cur_hours_check

1 个答案:

答案 0 :(得分:1)

使用TSQL进行基于集合的操作,我已经对您使用过的变量进行了修改,并在SQLFiddle设置了一个样本,用于完成拆分单个记录剩下的24小时多于24小时。这是工作:

BEGIN TRAN
INSERT INTO zt_Demonstrated_Capacity_Trend (
        -- The Columns we care about modifying
        period, Act_Batch_Time, Total_QT_Produced, KG_per_hour, Total_Possible_KG, Percent_of_Total_Hours
        -- The rest that you aren't touching in your procedure
        , Division, Region, Business_Region, Plant, Work_Center, DaysInMonth, Total_Possible_Hours, Demonstrated_Capacity, over_hours
    )
SELECT
    -- Add a day equal to the rows we generate
      DATEADD(dd,ShadowDays, Period) AS Shadow_Period
    -- Hours we generate
    , ShadowHours AS Shadow_Hours
    -- Our Hours times the rate is total produced
    , Kg_Per_Hour * ShadowHours AS Shadow_Total_QT_Produced
    -- Unmodified Kg_Per_Hour
    , Kg_Per_Hour
    -- Unmodified Kg_Per_Hour times 24 is total in a day possible.
    , Kg_Per_Hour * 24.0 as Total_Possible_KG
    -- Our hours divided by hours in a day
    , ShadowHours / 24.0 * 100 AS Shadow_Percent_of_Total_Hours
    -- the rest
    , Division, Region, Business_Region, Plant, Work_Center, DaysInMonth, Total_Possible_Hours, Demonstrated_Capacity, over_hours
FROM zt_Demonstrated_Capacity_Trend T
    CROSS APPLY (
        SELECT
            ROWID-1 AS ShadowDays
            , CASE WHEN CAST(T.Act_Batch_Time AS NUMERIC(38,15)) - ROWID*24 > 0 THEN 24 ELSE CAST(T.Act_Batch_Time AS NUMERIC(38,15)) % 24.0 END AS ShadowHours
        FROM (
            SELECT ROW_NUMBER()OVER(ORDER BY S.NAME) AS ROWID
            FROM master..spt_values S
            ) X
        WHERE T.Act_Batch_Time - ((ROWID-1)*24) > 0
    ) Z
WHERE T.Act_Batch_Time > 24

DELETE FROM zt_Demonstrated_Capacity_Trend WHERE Act_Batch_Time> 24
COMMIT TRAN

使用交叉应用,并获取我们可以分割给定值的人工行,然后我使用小时和天数以各种方式放入select语句以获得预期效果。您希望在单个事务中隔离它以防止insert和delete语句之间的新插入。这将比使用谓词的光标更好。