我正在研究一个与应用有关的体育赛事的“排行榜”,该体育赛事根据他们的分数报告前20位用户所有他们对多项选择测验的回应。它还在排行榜中显示当前用户自己的排名。MySQL:缓慢查询使用“group by” - 卡在“复制到tmp表”
当此应用程序正在进行负载测试时,有关的两个查询变得非常慢,在“复制到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过滤。此外,并非所有问题在回答时都有正确的答案。在未来某个时候可能会分配正确的答案,但无论如何在体育赛事结束时。系统报告用户选择每个答案的百分比。因此,以更加合计的方式存储分数的各种方式已被考虑但被丢弃,因为它们与一个或多个这些限制相冲突。
希望这足以去 - 许多感谢
感谢这个;感谢您的回复。我认为实现了一些模糊的类似的东西,但是在汇总表重新填充时,如果排行榜请求进入,会发生什么? – Polsonby 2012-01-17 15:40:25
你在使用InnoDB吗?如果是这样,您的更新查询将锁定您的汇总表,并且用户请求将在第二秒钟或之后挂起以生成它,然后正常完成。如果你正在使用MyISAM,你的存储过程应该可能显式地锁定汇总表以获得相同的效果。如果所有这些都出现了一个可怕的问题,您可以尝试创建一个新表格,然后锁定旧表格,删除它,并将新表格重新命名为旧名称。但这是一个全面的毛球来调试。 – 2012-01-18 02:41:57