0

我知道过去已经提出并解决了这个问题,但我无法将已经解决的问题完全应用于我的问题。

我正在尝试做的事情:

获取用户的全球排名以及低于和高于 10 的用户以及前 20 名用户 (ELO) 的最高排名。

我已经设法获得了前 20 名用户,但是在一次快速查询中获得单个用户的排名以及高于 10 名和低于他们 10 名的用户时遇到问题。此外,如果我有超过 1M 行,我怀疑使用 Rank over() 的速度有多快。最后,即使他们的 ELO 相同,任何玩家都不应该有相同的排名(因此是多重排序)。

下面是我的表

CREATE TABLE IF NOT EXISTS elo_ladder
(
    elo_ladder_incr INT NOT NULL AUTO_INCREMENT,
    player_id INT DEFAULT NULL,
    
    elo_rank INT DEFAULT 1000,
    elo_rank_wins INT DEFAULT 0,
    
    PRIMARY KEY (elo_ladder_incr),
    KEY elo_rank_key (elo_rank),
    KEY elo_rank_wins_key (elo_rank_wins),
    FOREIGN KEY (player_id) REFERENCES users(player_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

现在下面的查询是我获得前 20 名用户的查询。

// 获取排名靠前的玩家

  SELECT
    player_id,
    elo_rank,
    elo_rank_wins
  FROM elo_ladder
  ORDER BY 
  elo_rank DESC, 
  elo_rank_wins DESC
  LIMIT 20;

// 获取单人排名

SELECT
    *
FROM (
    SELECT
      player_id,
      t.elo_rank,
      (RANK() OVER (ORDER BY t.elo_rank DESC, t.elo_rank_wins DESC)) AS global_rank
    FROM (
      SELECT
        player_id,
        elo_rank,
        elo_rank_wins
      FROM elo_ladder
      GROUP BY player_id
    ) AS t
) AS rt
WHERE rt.player_id = 30;

最后,我使用的是 Mysql InnoDB。

4

1 回答 1

0
  1. 获取每个人的 RANK。这将用于派生表 ( FROM ( SELECT ... ))
  2. 围绕它构建一个带有 where 子句的 SELECT rank between user_rank - 10 and user_rank + 10

它可能ROW_NUMBER比 RANK 更好用,尤其是当您处理 RANK 与 DENSE_RANK 时。

您可能需要使用WITH临时表,添加索引可能会有所帮助。

但是处理超过一百万行的“排名”可能注定会很慢。

上面的步骤 2 可以替换为

( SELECT ... WHERE rank < user_rank ORDER BY rank DESC LIMIT 10 )
UNION ALL
( SELECT ... WHERE rank > user_rank ORDER BY rank ASC  LIMIT 10 )

此时,您不需要实际的“排名”,您可以简单地使用控制排名的指标。

祝你好运。

于 2021-03-17T06:09:31.387 回答