MySQL查询以大数据集更新玩家每周排名位置

问题描述

我正在尝试更新玩家的每周排名分数,但是我尝试的任何查询都会超时。表格中大约有10万行。我的桌子 players_weekly_rankings 看起来像这样:

player_id | ranking_points | yearweek | ranking_pos
22        | 1676           | 2020/01  | 1
12        | 1620           | 2020/01  | 2
45        | 1620           | 2020/01  | 2
53        | 1544           | 2020/01  | 4
25        | 1644           | 2020/02  | 1
21        | 1555           | 2020/02  | 2
etc.

所以rank_pos列就是要更新的列。

查询永远不会结束并运行到超时:

update players_weekly_ranking
set ranking_pos = (
    select count(distinct ranking_points) + 1
    from (SELECT ranking_points,yearweek FROM players_weekly_ranking) w2
    where w2.yearweek = players_weekly_ranking.yearweek and w2.ranking_points > players_weekly_ranking.ranking_points
)

并按以下要求进行解释(此测试tebale仅具有2000条记录,但实际表接近100k)

enter image description here

具有多达两千行的内容,它在两分钟内完成,但是超过此数,就会达到超时。

是否有更优化的方法来执行此操作,因此查询不会超时?谢谢!

解决方法

我相信这应该一次就可以解决问题(无子查询)

SET @rank = 0;

UPDATE players_weekly_ranking
SET ranking_pos = (@rank := @rank+1)
WHERE yearweek = '2020/01'
ORDER BY ranking_points DESC;

它定义了一个变量@rank,从0开始,然后通过降序yearweek遍历特定行ranking_points的所有行,并为其分配ranking_pos(@rank := @rank+1)可以在每一行增加变量。

编辑:我假设您只需要更新特定一周的排名,因为过去的分数不会改变

Edit2::以下版本考虑了均分,并且可以在数年的周内更新:

SET @rank = 0; -- rank of the previous row
SET @yearweek = ''; -- yearweek of the previous row
SET @last_score = 0; -- score of the previous row
SET @nb_same_score = 0; -- number of rows "in a row" with same score

UPDATE players_weekly_ranking
SET ranking_pos = IF(
        @yearweek != (@yearweek := yearweek),IF( -- if it's a new yearweek
            (@last_score := ranking_points) AND (@nb_same_score:=1),(@rank := 1),-- first row always gets ranking_pos = 1
            0
        ),IF( -- if same yearweek
            @last_score = (@last_score := ranking_points) AND (@nb_same_score := @nb_same_score + 1),@rank,-- if same score as last row => set same ranking_pos
            @rank := @rank + @nb_same_score + (@nb_same_score := 1) -1
        )
    )
ORDER BY yearweek,ranking_points DESC;

按照年份和周数对每一行进行迭代,这将执行以下操作:

  • 如果是新的一周,则第一行(最高分)的排名始终为1。({@yearweek采用新一周的值,@last_score@nb_same_score被重置)
  • 如果与最后一行在同一周,则将@last_score与该行的分数进行比较(并更新)。如果它们相等,则@nb_same_score递增
    • 如果相等,则该行的排名与上一行相同
    • 否则它将获得+ @nb_same_score的排名。 ((@nb_same_score := 1) -1只是将@nb_same_score变量重置为1)
,
  1. 用JOIN替换子查询
  2. 在JOIN'ed表中,使用窗口函数RANK()计算等级。它将完全满足您的需求。

RANK()仅在MySQL 8+ https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_rank

中可用

如果您具有MySQL 5. *,请查找不带RANK()函数的解决方法:Rank function in MySQL

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...