我可以做些啥来加快这个 SQL 查询的速度?
Posted
技术标签:
【中文标题】我可以做些啥来加快这个 SQL 查询的速度?【英文标题】:What can I do to speed up this SQL Query?我可以做些什么来加快这个 SQL 查询的速度? 【发布时间】:2012-10-30 14:44:44 【问题描述】:这里有一些细节,我尝试制作一个 SQLFiddle,但我的变量一直出错。这适用于 Sql Server 2008。我的问题是,我怎样才能使我的查询更快?我知道我在这里做错了很多事情(重复的嵌套查询),我希望有人来看看并帮助我将其从 30 分钟的执行时间中缩短! :-S
查询背后的基本思想是,在游戏中我想找到所有在一段时间内没有移动 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
【问题讨论】:
您可能会在 dba.stackexchange.com 上获得关于性能调整问题的更好答案 @RichardTheKiwi - 谢谢,我也会在那里发帖。 【参考方案1】:我要做的第一件事是实现sequenced
CTE,因为它在事物的整体架构中被使用了 4 次。
这意味着移动一些代码并使用#temp 表代替顺序 CTE。它还可以更好地工作一个数量级,因为您可以聚集 #temp 表并为 JOIN 创建有用的索引。
参见 this SQLFiddle,它表明 CTE 可以被评估多次,每次参考一次。
【讨论】:
实现它是什么意思?你有机会帮我一把吗?我还没有完全理解代码,移动很多东西可能会导致比我处理 atm 更多的错误! 感谢您的建议,将嵌套 CTE 更改为临时表将执行时间降低到更易于管理的 30 秒 :)以上是关于我可以做些啥来加快这个 SQL 查询的速度?的主要内容,如果未能解决你的问题,请参考以下文章
我正在运行一个 REST API 服务器,但我不太确定基础架构。另外,我可以做些啥来基准测试和提高速度?
我可以做些啥来优化适用于 Postgres 和 MySQL 的 SQL 查询?
我可以做些啥来加快我使用 NBomber 的负载测试? (VS LT 250 RPS 轻松;NBomber 最高 25 RPS)