MySQL查询指定玩家最高得分并计算排名的语句优化问题
问题解答
查询语句修改方案
你原来的语句问题是没有先提取该玩家的最高得分,同时默认按升序排序的逻辑大概率不符合常规排行榜「得分越高排名越靠前」的规则,修改后的可直接运行的代码如下:
兼容低版本MySQL(沿用FIND_IN_SET逻辑)
SELECT '4c8984f3-651a-48bc-ad1a-879624380fab' AS PlayerUUID, max_score AS score, FIND_IN_SET( max_score, (SELECT GROUP_CONCAT(DISTINCT iGamescore ORDER BY iGamescore DESC) FROM crystm_gameScoreboard) ) AS `rank` FROM ( -- 内层先查询目标玩家的最高得分 SELECT MAX(iGamescore) AS max_score FROM crystm_gameScoreboard WHERE PlayerUUID = '4c8984f3-651a-48bc-ad1a-879624380fab' ) AS t LIMIT 1;
说明:这里加了DISTINCT去重避免相同得分重复占位,排序改为DESC实现高分靠前的排名规则,如果你业务需要低分靠前,把DESC改回ASC即可。如果你的数据量超过10万条,GROUP_CONCAT会有默认长度限制,推荐使用MySQL 8.0+支持的窗口函数写法,性能更高无长度限制:
MySQL 8.0+ 优化版(窗口函数)
WITH player_max_score AS ( SELECT MAX(iGamescore) as max_score FROM crystm_gameScoreboard WHERE PlayerUUID = '4c8984f3-651a-48bc-ad1a-879624380fab' ), score_rank AS ( SELECT iGamescore, DENSE_RANK() OVER(ORDER BY iGamescore DESC) as `rank` FROM crystm_gameScoreboard GROUP BY iGamescore ) SELECT '4c8984f3-651a-48bc-ad1a-879624380fab' AS PlayerUUID, m.max_score as score, r.`rank` FROM player_max_score m LEFT JOIN score_rank r ON m.max_score = r.iGamescore;
业务存储方案选择
两种方案各有适用场景,优缺点如下:
- 每次新增得分记录:
- 优势:可留存玩家所有历史战绩,支持战绩查询、多周期排行榜(周/月榜)、用户游戏行为分析、数据问题回溯等扩展需求
- 劣势:表数据量增长快,全表查询性能会随数据量上升下降,需要额外做分表、归档或缓存优化
- 仅更新玩家历史最高分:
- 优势:每个玩家仅一条数据,表体积小,查询最高分和排行榜性能极高,实现逻辑简单
- 劣势:丢失所有历史游戏数据,无法支撑需要历史记录的扩展业务,数据出错无回溯路径
建议:如果后续有扩展业务需求,优先选新增记录的方案,可以额外维护一张玩家最高分快照表(实时/定时更新)兼顾性能和扩展性;如果仅需要总排行榜功能无其他扩展需求,选更新最高分的方案更高效。
内容的提问来源于stack exchange,提问作者Lato
相关产品推荐
相关产品推荐

