我有一个查询,根据列的值计算密集排名:
SELECT id,
score1,
FIND_IN_SET
(
score1,
(
SELECT GROUP_CONCAT(score1 ORDER BY score1 DESC) FROM scores
)
) as rank
FROM score_news;
这是查询结果的样子:
+----+--------+------+
| id | score1 | rank |
+----+--------+------+
| 1 | 15 | 1 |
| 2 | 15 | 1 |
| 3 | 14 | 3 |
| 4 | 13 | 4 |
+----+--------+------+
当分数数量增加N倍时,查询将花费Nx的时间。有什么办法可以优化这个吗?我的 table 大小约为 106
注意:我已经尝试过使用 mysql 用户变量的技术,但是当我在大型集合上运行它时,我得到了不一致的结果。经过调查,我在 MySQL 文档中发现了这一点:
The order of evaluation for user variables is undefined and may change based on the elements contained within a given query. In SELECT @a, @a := @a+1 ..., you might think that MySQL will evaluate @a first and then do an assignment second, but changing the query (for example, by adding a GROUP BY, HAVING, or ORDER BY clause) may change the order of evaluation...The general rule is never to assign a value to a user variable in one part of a statement and use the same variable in some other part of the same statement. You might get the results you expect, but this is not guaranteed.
我对用户变量的尝试:
SELECT
a.id,
@prev := @curr as prev,
@curr := a.score1 as curr,
@rank := IF(@rank = 0, @rank + 1, IF(@prev > @curr, @rank+@ties, @rank)) AS rank,
@ties := IF(@prev = @curr, @ties+1, 1) AS ties
FROM
scores a,
(
SELECT
@curr := null,
@prev := null,
@rank := 0,
@ties := 1,
@total := count(*)
FROM scores
WHERE score1 is not null
) b
WHERE
score1 is not null
ORDER BY
score1 DESC
)
最佳答案
使用变量的解决方案可以工作,但您需要首先对结果集进行排序,然后才然后处理变量分配:
SELECT a.id,
@rank := IF(@curr = a.score1, @rank, @rank + @ties) AS rank,
@ties := IF(@curr = a.score1, @ties + 1, 1) AS ties,
@curr := a.score1 AS curr
FROM (SELECT * FROM scores WHERE score1 is NOT NULL ORDER BY score1 DESC) a,
(SELECT @curr := null, @rank := 0, @ties := 1) b
注意:我将 curr
列放在 select
子句的最后以保存一个变量。
关于mysql - FIND_IN_SET 与 GROUP_CONCAT 太慢(MySQL 中的密集排名),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47468262/