我正在我的应用程序中实现一个排行榜,我想每隔几次更新一次。 为此,我创建了两个排行榜的表格,每个人都看起来像这样:
user_id, score, rank
这是我的更新查询:
select score from leaderboard order by score for update;
select(@rankCounter := 0);
update leaderboard set rank = (select(@rankCounter := @rankCounter + 1)) order by score desc;
我正在使用活动表进行查询,并且每次都会切换活动表。
此更新目前大约需要3分钟(在我的机器上)以更新4M原始数据。 我希望减少所需的CPU数量,而且我不关心更新需要更长的时间。
我该怎么做?
答案 0 :(得分:0)
我建议您尝试添加索引... ON leaderboard (score)
,以避免排序操作。我还建议您从UPDATE语句中删除不必要的SELECT(但我不知道它是否有任何性能影响,但在该上下文中不需要SELECT关键字。
排序操作肯定会使用一些CPU。我不清楚优化器是否忽略了UPDATE语句中的SELECT,或者计划是否与那里的(不必要的?)SELECT有所不同。 (在该上下文中包含SELECT关键字的目的是什么?)
此外,没有必要从每一行返回得分值以获取排行榜表中所有行的锁定。 SELECT语句上的ORDER BY也可能占用CPU周期(如果没有带score
的索引作为前导列.4M行结果集的不必要准备也消耗CPU周期。
当UPDATE语句本身将获得必要的锁时,为什么必须使用SELECT ... FOR UPDATE来获取表中所有那些行的锁定是不必要的。 (SELECT ... FOR UPDATE语句只会在BEGIN TRANSACTION的上下文中获取锁,或者如果禁用了自动提交。(我假设leaderboard
是InnoDB表。)
MySQL可以使用索引来避免排序操作:
CREATE INDEX leaderboard_IX1 ON leaderboard (score) ;
这应该足以更新排名列:
SET @rankCounter := 0;
UPDATE leaderboard
SET rank = @rankCounter := @rankCounter + 1
ORDER BY score DESC ;