【发布时间】:2012-02-12 04:21:38
【问题描述】:
我正在为一个与体育赛事相关的网络应用程序制作“排行榜”,该应用程序根据他们对多项选择测验的所有回答的得分报告前 20 名用户。它还会显示当前用户自己在排行榜中的排名。
在对该应用程序进行负载测试时,相关的两个查询变得非常慢,花费大量时间处于“复制到 tmp 表”状态(每个查询最多 20 秒)。它们最终确实会处理,但同时数百个可能会堆积起来。
单独给定响应表中合理数量的行,每个查询大约需要 1 秒来执行(25K 用户,例如响应中的 200K 行)
我已经为相关表添加了一些索引,特别是对于 FK 列和 where 语句中使用的任何内容。我还在响应表中添加了 userID、answerID 的覆盖索引。
这是排行榜本身的查询
SELECT users.username, sum(questions.points) as score FROM responses
JOIN answers on responses.answerID = answers.answerID
JOIN questions on answers.questionID = questions.questionID
JOIN users on responses.userID = users.userID
WHERE users.username != '' AND answers.isCorrect
GROUP BY users.userID
ORDER BY score DESC
LIMIT 20
这是获取用户自己在结果中的排名的查询;一个单独的查询首先获取他们的分数,然后我们计算有多少用户的分数更高。
Select count(*) +1 as rank from (
SELECT users.username, sum(questions.points) as score
FROM responses
JOIN answers on responses.answerID = answers.answerID
JOIN questions on answers.questionID = questions.questionID
JOIN users on responses.userID = users.userID
WHERE users.username != '' AND answers.isCorrect
GROUP BY users.userID
HAVING sum(questions.points) > 2431
ORDER BY score DESC
) as result
简化的架构是
QUESTIONS
questionID
question
points
ANSWERS (multiple choice answers for question)
answerID
questionID
answer
isCorrect
RESPONSES (the player's choice of answer)
responseID
answerID
userID
我认为这些查询是以一种模糊合理的方式完成的,但我想知道是否有明显更好的方式来执行我没有考虑过的其中任何一个。
另外,有没有人知道为什么这些查询会在“复制到 tmp 表”状态下堆积起来,并且在服务器负载过重时需要很长时间才能处理?我认为它可能是在磁盘上创建它们,但我看到这是一个单独的状态消息。我用过 EXPLAIN 但我的感觉是临时表是这些查询不可避免的;因此想知道“复制到 tmp 表”需要很长时间
约束:未显示,用户有 teamID,查询也由 teamID 过滤。也未显示,有几个事件,这些查询也可以通过 eventID 过滤。此外,并非所有问题在回答时都有正确答案。正确的答案可能会在未来的某个时间分配,但无论如何要在体育赛事结束时分配。系统报告选择每个答案的用户百分比。因此,人们考虑了各种以更汇总的方式存储分数的方法,但由于它们与这些约束中的一个或多个冲突,因此被丢弃了。
希望这足以继续 - 非常感谢
【问题讨论】:
标签: mysql sql performance