2012-10-30 54 views
1

下面是一些细节,我试图做一个SQLFiddle,但我不断收到我的变量的错误。这在Sql Server 2008中有效。我的问题是,我怎样才能让我的查询更快?我知道我在这里做了许多错误的事情(重复的nester查询),我希望能让某人看一看,并帮助我从30分钟的执行时间中解脱出来。 :-S我能做些什么来加速这个SQL查询?

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

该查询有效,但它是AND NOT EXISTS子句,它放慢了抓取的速度,之后我添加了它需要16秒才能运行! 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

对于性能调整问题,您可能会在dba.stackexchange.com上得到更好的答案 – RichardTheKiwi

+0

@RichardTheKiwi - 谢谢,我也会在那里发帖。 – Faraday

回答

3

的我要做的第一件事是实现CTE,因为它在事物的整体模式中使用了4次。

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

参见this SQLFiddle,其显示CTE可以被评估多次,每次参考一次。

+0

实现它意味着什么?你有什么机会可以帮我一把吗?我并没有完全将自己的头脑包裹在代码中,移动很多东西可能会导致比我能处理的更多的错误! – Faraday

+0

感谢您的建议,将嵌套的CTE更改为临时表,将执行时间缩短到更易于管理的30秒:) – Faraday

相关问题