我该怎么做才能加快这个SQL查询的速度?

时间:2012-10-30 14:44:45

标签: sql sql-server sql-server-2008 exists

这里有一些细节,我试图制作一个SQLFiddle,但我的变量一直出错。这适用于Sql Server 2008.我的问题是,如何让我的查询更快?我知道我在这里犯了很多错误(重复的nester查询),我希望有人看看并帮助我从30分钟的执行时间中解决这个问题! :-S

查询背后的基本思想是,在游戏中我想找到所有在一段时间内没有移动过5个单位的玩家,他们在停止行动并且在停止移动之前没有开火60分钟

查询有效,但是在我添加它需要16秒才能运行之前,它是AND NOT EXISTS子句,它会减慢爬行速度! 16秒仍然很长一段时间,所以任何其他的改进都会受到赞赏,但是现在这是我自己的POC游戏(只是把点点滴滴在一起),16秒是可以接受的......

DECLARE @n INT , @DistanceLimit INT
SELECT  @n = 2 , @DistanceLimit = 5;

WITH    partitioned
          AS ( SELECT   * ,
                        CASE WHEN Distance < @DistanceLimit THEN 1
                             ELSE 0
                        END AS PartitionID
               FROM     EntityStateEvent
               WHERE    ExerciseID = '8B50D860-6C4E-11E1-8E70-0025648E65EC'
             ),
        sequenced
          AS ( SELECT   ROW_NUMBER() OVER ( PARTITION BY PlayerID ORDER BY EventTime ) AS MasterSeqID ,
                        ROW_NUMBER() OVER ( PARTITION BY PlayerID, PartitionID ORDER BY EventTime ) AS PartIDSeqID ,
                        *
               FROM     partitioned
             ),
        filter
          AS ( SELECT   MasterSeqID - PartIDSeqID AS GroupID ,
                        MIN(MasterSeqID) AS GroupFirstMastSeqID ,
                        MAX(MasterSeqID) AS GroupFinalMastSeqID ,
                        PlayerID
               FROM     sequenced
               WHERE    PartitionID = 1
               GROUP BY PlayerID ,
                        MasterSeqID - PartIDSeqID
               HAVING   COUNT(*) >= @n
             )
    SELECT
DISTINCT    ( sequenced.PlayerID ) ,
            MIN(sequenced.EventTime) AS StartTime ,
            MAX(sequenced.EventTime) AS EndTime ,
            DATEDIFF(minute, MIN(sequenced.EventTime),
                     MAX(sequenced.EventTime)) AS StaticTime ,
            Player.Designation AS 'Player'
    FROM    filter
            INNER JOIN sequenced ON sequenced.PlayerID = filter.PlayerID
                                    AND sequenced.MasterSeqID >= filter.GroupFirstMastSeqID
                                    AND sequenced.MasterSeqID <= filter.GroupFinalMastSeqID
            INNER JOIN Events ON Events.FiringPlayerID = sequenced.PlayerID 
            INNER JOIN Player ON Player.PlayerID = sequenced.PlayerID
                                 AND Player.Force = 'FR'
                                 AND NOT EXISTS ( SELECT    *
                                                  FROM      Events
                                                  WHERE     Events.FiringPlayerID = Player.PlayerID
                                                  GROUP BY  Events.FiringTime
                                                  HAVING    Events.FiringTime BETWEEN DATEADD(minute,
                                                              -60,
                                                              ( SELECT
                                                              MIN(s.EventTime)
                                                              FROM
                                                              sequenced s
                                                              WHERE
                                                              s.PlayerID = filter.PlayerID
                                                              AND s.MasterSeqID >= filter.GroupFirstMastSeqID
                                                              AND s.MasterSeqID <= filter.GroupFinalMastSeqID
                                                              ))
                                                              AND
                                                              ( SELECT
                                                              MIN(s.EventTime)
                                                              FROM
                                                              sequenced s
                                                              WHERE
                                                              s.PlayerID = filter.PlayerID
                                                              AND s.MasterSeqID >= filter.GroupFirstMastSeqID
                                                              AND s.MasterSeqID <= filter.GroupFinalMastSeqID
                                                              ) )
            INNER JOIN Player HitPlayer ON HitPlayer.PlayerID = Events.HitPlayerID
    WHERE   HitPlayer.[FORCE] = 'HO'
    GROUP BY GroupID ,
            sequenced.PlayerID ,
            Events.FiringPlayerID ,
            Events.FiringTime ,
            Player.Designation
    HAVING  DATEDIFF(minute, MIN(sequenced.EventTime),
                     MAX(sequenced.EventTime)) > 5
            AND Events.FiringTime BETWEEN MIN(sequenced.EventTime)
                                  AND     MAX(sequenced.EventTime)
    ORDER BY StartTime

1 个答案:

答案 0 :(得分:3)

我要做的第一件事就是实现sequenced CTE,因为它在整体架构中使用了4次。

这意味着移动一些代码并使用#temp表代替顺序CTE。由于您可以聚合#temp表并为JOIN创建有用的索引,因此它的效果也会提高一个数量级。

请参阅this SQLFiddle,其中显示可以多次评估CTE,每次参考一次。