Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL:使用“慢查询”;按“分组”卡在;“复制到tmp表”;_Mysql_Sql_Performance - Fatal编程技术网

MySQL:使用“慢查询”;按“分组”卡在;“复制到tmp表”;

MySQL:使用“慢查询”;按“分组”卡在;“复制到tmp表”;,mysql,sql,performance,Mysql,Sql,Performance,我正在为一个与体育赛事相关的网络应用程序制作一个“排行榜”,该排行榜根据用户在多项选择题测验中的得分来报告前20名用户。它还显示当前用户自己在排行榜中的排名 当这个应用程序正在进行负载测试时,相关的两个查询变得非常慢,在“复制到tmp表”状态下花费大量时间(每个查询最多20秒)。他们最终会处理这个过程,但在此期间,数百人可以叠加在一起 如果responses表中的行数合理,则执行每个查询大约需要1秒(25K个用户,例如responses中的200K行) 我已经为相关的表添加了一些索引,特别是对于

我正在为一个与体育赛事相关的网络应用程序制作一个“排行榜”,该排行榜根据用户在多项选择题测验中的得分来报告前20名用户。它还显示当前用户自己在排行榜中的排名

当这个应用程序正在进行负载测试时,相关的两个查询变得非常慢,在“复制到tmp表”状态下花费大量时间(每个查询最多20秒)。他们最终会处理这个过程,但在此期间,数百人可以叠加在一起

如果responses表中的行数合理,则执行每个查询大约需要1秒(25K个用户,例如responses中的200K行)

我已经为相关的表添加了一些索引,特别是对于FK列和where语句中使用的任何内容。我还在responses表中添加了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进行过滤。此外,并非所有问题在回答时都有正确答案。正确的答案可能会在将来的某个时间点分配,但无论如何都会在体育赛事结束时分配。系统报告选择每个答案的用户百分比。因此,以更聚合的方式存储分数的各种方法已被考虑,但由于它们与一个或多个约束冲突,因此被放弃


希望这足够继续下去-非常感谢

我做过类似的事情,也遇到过类似的问题。同时查询会堆积起来,因为它们需要序列化,所以每个查询在运行时都会返回正确的结果

在负载测试中而不是在生产中捕获它,这对您很有好处

你如何解决这个问题

  • 创建与摘要查询结果具有相同列的摘要表
  • 创建存储过程以从明细表中提取汇总数据并重写汇总表
  • 创建一个事件以在适当的时间间隔运行存储过程。你的排行榜显示有多陈旧?六秒钟,一分钟,一小时?这就是您的活动应该运行的频率。你的问题不是排行榜抽取查询的基本成本。问题在于试图一分钟运行无数次
  • 重写你的排行榜显示,从汇总表中删除内容
  • 这样,你就可以为每个人做一次硬的事情,为每个用户做一次简单的事情

    这将稳定您的应用程序并使其能够很好地扩展。

    请看

    如果存在ORDERBY子句和不同的GROUPBY子句,MySQL将使用temp table,在这里列出的其他情况下也是如此。你不能绕过它

    因此,在您的情况下,最简单的解决方案可能是设置一个RAM磁盘并使MySQL将临时表存储在那里,如中所述:


    谢谢你;谢谢你的答复。我曾经考虑过实现一些类似的东西,但是当重新填充汇总表时出现排行榜请求时会发生什么呢?您使用的是InnoDB吗?如果是这样,更新查询将锁定汇总表,用户请求将在生成汇总表的第二秒左右挂起,然后正常完成。如果您使用的是MyISAM,您的存储过程可能会显式锁定汇总表以获得相同的效果。如果所有这些都出现了可怕的问题,您可以尝试创建一个新表,然后锁定旧表,删除它,并将新表重命名为旧表的名称。但这完全是一个需要调试的问题。