python - 优化此 MySQL 查询的最佳方法是什么?

标签 python mysql django performance

这是一个查询,用于汇总每个玩家的游戏结果并显示符合条件的玩家。

select   *, 
         (kills / deaths)  as killdeathratio, 
         (totgames - wins) as losses 
from     (select   gp.name              as name, 
                   gp.gameid            as gameid, 
                   gp.colour            as colour, 
                   Avg(dp.courierkills) as courierkills, 
                   Avg(dp.raxkills)     as raxkills, 
                   Avg(dp.towerkills)   as towerkills, 
                   Avg(dp.assists)      as assists, 
                   Avg(dp.creepdenies)  as creepdenies, 
                   Avg(dp.creepkills)   as creepkills, 
                   Avg(dp.neutralkills) as neutralkills, 
                   Avg(dp.deaths)       as deaths, 
                   Avg(dp.kills)        as kills, 
                   sc.score             as totalscore, 
                   Count(* )            as totgames, 
                   Sum(case 
                         when ((dg.winner = 1 and dp.newcolour < 6) or 
                               (dg.winner = 2 and dp.newcolour > 6)) 
                         then 1 
                         else 0 
                       end) as wins 
          from     gameplayers as gp, 
                   dotagames   as dg, 
                   games       as ga, 
                   dotaplayers as dp, 
                   scores      as sc 
          where    dg.winner <> 0 
                   and dp.gameid = gp.gameid 
                   and dg.gameid = dp.gameid 
                   and dp.gameid = ga.id 
                   and gp.gameid = dg.gameid 
                   and gp.colour = dp.colour 
                   and sc.name   = gp.name 
          group by gp.name 
          having   totgames >= 30
          ) as h 
order by totalscore desc

现在我不太确定最好的方法是什么,但您认为优化此查询的方法是什么?

我运行 Q6600 @ 2.4ghz、4gb 内存、64 位 Linux Ubuntu 9.04 系统,这个查询最多可能需要 6.7 秒才能运行(我有一个巨大的数据库)。

我也想对结果进行分页,在此查询之上执行额外的条件太慢了....

我使用 django 作为前端,所以任何包括使用 python +/- django 方法的方法都会很棒。也欢迎 MySQL、Apache2 调整。当然,我愿意更改查询以使其运行得更快。

感谢阅读我的问题;期待阅读您的答案!

编辑:解释查询结果

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra 
1   PRIMARY     <derived2>  ALL     NULL    NULL    NULL    NULL    783     Using filesort
2   DERIVED     sc  ALL     name,name_2     NULL    NULL    NULL    2099    Using temporary; Using filesort
2   DERIVED     gp  ref     gameid,colour,name  name    17  development.sc.name     2    
2   DERIVED     ga  eq_ref  PRIMARY,id,id_2     PRIMARY     4   development.gp.gameid   1   Using index
2   DERIVED     dg  ref     gameid,winner   gameid  4   development.ga.id   1   Using where
2   DERIVED     dp  ref     gameid_2,colour     gameid_2    4   development.ga.id   10  Using where

最佳答案

首先,SQL 格式错误。最明显的错误是每个 AS 子句之前的行拆分。第二个明显的问题是使用隐式连接而不是显式使用 INNER JOIN ... ON ...

现在回答实际问题。

在不知道数据或环境的情况下,我首先要看的是一些 MySQL 服务器设置,例如 sort_bufferkey_buffer。如果您没有更改任何这些,请继续阅读它们。默认值非常保守,通常可以提高到默认值的十倍以上,尤其是在像您这样的大型熨斗上。

回顾之后,我将运行部分查询以查看速度以及 EXPLAIN 所说的内容。索引的影响可能是深远的,但 MySQL 有一个“手指和脚趾”问题,它不能在每个表中使用多个索引。带过滤功能的 JOIN 可能需要两个。所以它必须下降到行扫描以进行其他检查。但话虽如此,将查询切分并尝试不同的组合会告诉您它从哪里开始出现问题。

现在您将了解“临界点”可能在哪里:这是一些原始数据大小的小幅增加,例如需要提取多少,将导致性能大幅下降,因为某些内部结构变得太大了。此时,您可能希望增加临时表的大小。请注意,这种优化有点像魔法。 :-)

然而,还有另一种方法:反规范化。在一个简单的实现中,定期调度的脚本会不时地运行这个昂贵的查询,并将数据插入一个单独的表中,其结构更接近您想要显示的内容。这种方法有多种变体。可以在应用程序中或使用表触发器随时保持最新状态。在另一个极端,您可以允许您的应用程序偶尔运行昂贵的查询,但将结果缓存一会儿。如果很多人经常调用它,这是最有效的:即使是每秒运行 15 次的请求的 2 秒缓存也会显示出明显的改进。

您可以找到生成相同数据的方法,方法是运行六个查询,每个查询返回一些数据,然后对数据进行后处理。您还可以运行返回更多数据的原始查询版本(这可能会更快,因为它进行的过滤更少)并对其进行后处理。我多次发现五个更简单、更小的查询比一个试图完成所有操作的大查询要快得多——一个数量级,有时是两个数量级。

关于python - 优化此 MySQL 查询的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1191105/

相关文章:

javascript - 在 JavaScript 中保护 Azure API 剩余调用

python - 未找到 Mongod.service => 从空双端队列弹出 => 身份验证失败

mysql - 在 MySql 中删除未命名的外键

javascript - 如何通过php和ajax创建通知?

javascript - 显示代码的 Django 模板

python - 尝试以特定顺序和格式打印字典中的信息

python - 使用 Raptor 或 Sax 验证 RDF 文件

mysql - 从 vb.net 数据读取器中的多个表读取

django javascript 本地化问题

python - Django - 关系 "relation"不存在。无法运行 python manage.py migrate?