我正在根据输入参数计算分数,并对它们进行排序,以获得前10名运动员的列表。查询分数很快(大约<100 ms)。但当我开始排序时查询需要>1.5秒(对我来说太慢了)。
所以我得到了一个乒乓球运动员
athlete
idAthlete | name
1 | foo
2 | bar
和表结果
result
idResult | idAthlete | place | type
1 | 1 | 2 | World championship
2 | 3 | 1 | European championship
在我的数据库中,我有~40000个条目表结果
和查询
SELECT athlete.idAthlete,
SUM(IF((FIND_IN_SET(result.type, @compTypes)), GETSCORE(result.place), 0)) AS score
FROM
athlete
LEFT JOIN result ON result.idPerson = athlete.idAthlete
GROUP BY athlete.idAthlete
ORDER BY score desc
LIMIT 10;
@compTypes是"World championship,European championship,…"形式的字符串
我尝试在临时表中存储没有order by子句的结果,然后对其进行排序。这种方法有效,但速度并不快。
我将非常感谢任何建议。我在这个问题上坐了一段时间,可能忘记了一些明显的东西。谢谢你:)
有多少运动员?这是必须排序的行数。这个数越小,排序越快。所以,如果你能限制潜在的前10名,排序可能会快得多。
这是我如何写你的查询。不同之处在于我只连接我们想要考虑的类型的结果。(然而,这不会加快排序速度。)
select a.idathlete, coalesce(sum(getscore(r.place)), 0) as score
from athlete a
left join result r on r.idathlete = a.idathlete and find_in_set(r.type, @comptypes)
group by a.idathlete
order by score desc
limit 10;
如果可以只显示有结果的运动员,则从查询中删除athletes
表:
select idperson, sum(getscore(place)) as score
from result
where find_in_set(type, @comptypes)
group by idperson
order by score desc
limit 10;
如果可以进一步将此限制为得分至少为n的运动员,则添加HAVING
子句。下面是n= 100的示例:
group by idperson
having score >= 100
order by score desc
limit 10;
值n越高,要排序的行越少。
为了有效的数据访问,我将提供这些索引:
create index idx1 on athlete (idathlete);
create index idx2 on result (idperson, type, place);
create index idx3 on result (type, idperson, place);
由于idathlete
显然是表athlete
的主键,您应该已经有索引idx1了。
根据查询和数据,将使用idx2或idx3,或者两者都不使用。用EXPLAIN
检查这一点,并删除未使用的一个(s)。