我有一个根据列值计算密集排名的查询:
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更长的时间。有什么办法可以优化吗?我的桌子大小为10 6 功能
注意:我已经尝试过使用mysql用户变量的技术,但是当我在大型集合上运行它时会得到不一致的结果。经过调查,我在MySQL文档中发现了这一点:
用户变量的评估顺序未定义,可能会更改 基于给定查询中包含的元素。在SELECT @ a,@ a := @ a + 1 ...,你可能会认为MySQL会首先评估@a和 然后做第二个任务,但更改查询(例如,通过 添加GROUP BY,HAVING或ORDER BY子句可能会改变顺序 评估...一般规则是永远不要为用户分配值 变量在一个语句的一部分中,并在一些语句中使用相同的变量 同一声明的其他部分。你可能会得到你的结果 期待,但这不能保证。
我尝试使用用户变量:
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
)
答案 0 :(得分:0)
带变量的解决方案可行,但您需要首先对结果集进行排序,只有然后才能使用变量赋值:
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
子句的最后一行以保存一个变量。
答案 1 :(得分:0)