mysql 分组查询取各分组的前两名及子查询性能优化

背景:由于项目运营需要提供各个球员(playerId)跑动距离(distance)最长的前两场比赛数据记录:

数据存在mongojg表中下面看第一版sql:

1.一开始不知道怎么取跑动最好的前两场数据所以通过取表现最好的比赛然后通过id从结果集排除再对剩下的比赛取最好表现,最后将两次结果合并的到球员表现最好的两场比赛(不多说都是泪)...

SELECT e.ids,
	e.matchId,
	e.playerId,
	e.distance 跑动距离,
	e.printSpeedDistance,
	e.highSpeedDistance,
	( e.printSpeedDistance + e.highSpeedDistance ) 高强度跑动距离,
	e.successPass 成功传球次数,
	e.tackles 阻截 ,
	b.`name` from  mongojg e JOIN qiuyaunxinxix b ON e.playerId = b.id
	JOIN sheet1 c ON b.`name` = c.`球员` 
WHERE e.distance in 
(SELECT
	
	max(a.distance) 跑动距离
	 
FROM
	mongojg a
	JOIN qiuyaunxinxix b ON a.playerId = b.id
        GROUP BY a.playerId ORDER BY a.playerId);

第二版逻辑:

后来通过子查询的方式实现了取每个球员最好的两场比赛,不多说直接放sql:

SELECT  matchId, playerId,b.`name` 球员, distance 跑动距离,
( mj.printSpeedDistanceCounts + mj.highSpeedDistanceCounts ) 高强度跑动距离次数,
mj.successPass 成功传球次数,
	mj.tackles 阻截 
from  mongojg mj 
JOIN qiuyaunxinxix b on mj.playerId=b.id
WHERE (
SELECT COUNT(1) from mongojg mn  
WHERE mj.playerId=mn.playerId AND mj.distance<mn.distance 
)<2
ORDER BY  mj.playerId;

可以看到第二版sql比第一版逻辑清晰了很多:加入子查询找出子表中距离比原表大的记录并在这些记录中取前两个记录;


看看执行记录:执行时间1.306s,使用了子查询,下面怎么将子查询改写为left join

优化三:

SELECT 
	mj.matchId,
	mj.playerId,
	b.`name` as 球员,
	mj.distance 跑动距离,mn.distance,
	( mj.printSpeedDistanceCounts + mj.highSpeedDistanceCounts ) 高强度跑动距离次数,
	mj.successPass 成功传球次数,
	mj.tackles 阻截 
FROM
	mongojg mj
	JOIN qiuyaunxinxix b ON mj.playerId = b.id 
	LEFT  JOIN mongojg mn on mj.playerId=mn.playerId and mn.distance > mj.distance
  GROUP BY mj.matchId, mj.playerId ,mj.distance
	HAVING COUNT(mn.matchId)<2
ORDER BY
	mj.playerId;


执行时间:0.291s,可以看到改为left join连接后效率提升明显;

下一波优化为主表playerId 添加索引:

ALTER TABLE `haha`.`mongojg` ADD INDEX `index`(`playerId`) USING BTREE;


执行时间:时间: 0.017s

猜你喜欢

转载自blog.csdn.net/sinat_41780498/article/details/79956561