While子句中的性能问题

时间:2013-06-20 19:03:53

标签: sql-server performance table-variable

好的,大家,

提前道歉。不过,这个实际上很有趣。

我写了一个我昨天半自豪的SQL脚本,因为我觉得它非常聪明。事实证明它会因性能问题而受到破坏,因此我甚至无法测试它,因此它甚至可能无法实现我认为的叹息

最好用一个例子解释这个问题:

A列| B栏| C列| D栏

   Heart   |      K      |  2/1/2013  |   3/1/2013
   Heart   |      K      |  2/1/2013  |   3/1/2013
   Heart   |      K      |  1/1/2013  |   3/1/2013
   Heart   |      K      |  2/1/2013  |   4/1/2013
   Spade   |      4      |  2/1/2013  |   3/1/2013
   Spade   |      3      |  2/1/2013  |   3/1/2013
   Club    |      4      |  2/1/2013  |   3/1/2013

使用此表我需要:1。从第一个开始,如果列A中的值匹配,则使用后面的数据更新行; 2.如果匹配则删除更新后的第二行,以及3如果没有匹配则转到下一行并重新运行相同的过程。

如果匹配,则较高的行会根据以下内容进行更新:

  1. A栏:没什么
  2. B列:如果两个值相同,请将值保持为1,否则请写入“Multiple”
  3. C栏:保持两者之间的较早日期,
  4. D栏:保持两者之间的日期,
  5. 然后我删除了下一行。

    我的例子应该产生以下结果:

    A列| B栏| C列| D栏

       Heart   |      K      |  1/1/2013  |  4/1/2013
       Spade   |   Multiple  |  2/1/2013  |   3/1/2013
       Club    |      4      |  2/1/2013  |   3/1/2013
    

    为了完成所有这些,我创建了两个表变量,将相同的数据插入到两者中,然后循环访问第二个(@ScheduleB),查找匹配以更新第一个表中的行(@ScheduleA)。然后我删除了@A中行下面的行(因为它与B相同)。最后,当没有匹配时,我移动到@A的下一行开始该过程。至少这是代码应该做的 - 见下文。

    问题是性能是可怕的。我考虑过使用Cursor,但不知道性能是否有帮助。

    有什么建议吗?

    Declare @ScheduleA Table
    (
        RowNumber int,
        Period nvarchar(MAX),
        Program nvarchar(MAX),
        ControlAccount Nchar(50),
        WorkPackage Nchar(50),
        CAM Nchar(50),
        EVM Nchar(50),
        Duration int,
        BLStart datetime,
        BLFinish datetime
    )
    
    Declare @ScheduleB Table
        (
            RowNumber int,
            Period nvarchar(MAX),
            Program nvarchar(MAX),
            ControlAccount Nchar(50),
            WorkPackage Nchar(50),
            CAM Nchar(50),
            EVM Nchar(50),
            Duration int,
            BLStart datetime,
            BLFinish datetime
        )
    
    Insert INTO @ScheduleA
    Select ROW_NUMBER() OVER(order by workpackage desc) as [Row], Period, Program,       
    ControlAccount, WorkPackage, CAM, EVM, Duration, BLStart, BLFinish
    From ScheduleData 
    where program = @Program and period = @Period
    
    Insert INTO @ScheduleB
    Select ROW_NUMBER() OVER(order by workpackage desc) as [Row], Period, Program,   
    ControlAccount, WorkPackage, CAM, EVM, Duration, BLStart, BLFinish
    From ScheduleData 
    where program = @Program and period = @Period
    
    declare @i int = 1
    declare @j int = 2
    
    --Create a loop for the second variable that counts up to the last row of the B table
    While @j < (select MAX(ROWNUMBER) + 1 from @ScheduleB)
    Begin
    --if the tables match by WorkPackage THEN
    IF ((select WorkPackage from @ScheduleA where RowNumber = @i) = 
        (select workpackage from @ScheduleB where RowNumber = @j))
        Begin 
            Update @ScheduleA 
     --Update the Schedule CAM, BLStart, BLFinish of     the A table (if necessary)
    set CAM = 
        Case
                   --Set values in @ScheduleA Column B based on logic
            End,
    
    BLStart = 
            Case
                   --Set values in @ScheduleA Column C  based on logic
        End,
    
    BLFinish = 
        Case
                   --Set values in @ScheduleA Column D based on logic
                End
        Where RowNumber = @i
    
    Delete from @ScheduleA 
    where RowNumber = @i + 1
    
    set @j = @j + 1 --next row in B
    End
    ELSE 
    set @i = @i + 1
    END
    

    编辑:为了澄清,B列不是整数列,我只是以此为例,因为很容易理解卡片。我已经更新了专栏,包括K.

1 个答案:

答案 0 :(得分:3)

根据您的要求,我认为这样的解决方案可行:

SELECT 
    [column a], 
    CASE WHEN MAX([column b]) <> MIN([column b]) THEN 'multiple' ELSE CAST(MAX([column b]) AS NVARCHAR(10)) END,
    MIN([column c]), 
    MAX([column d]) 
FROM Table
GROUP BY [column a]

修改

SQL Fiddle