这是一个总结游戏中每个玩家游戏结果的查询,并显示符合条件的玩家。
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调整也很受欢迎。当然,我愿意更改查询以使其运行更快。
感谢您阅读我的问题;期待阅读你的答案!
编辑:EXPLAIN QUERY RESULTS
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
答案 0 :(得分:2)
首先,SQL格式错误。最明显的错误是每个AS
子句之前的行拆分。第二个明显的问题是使用隐式连接而不是显式使用INNER JOIN ... ON ...
。
现在回答实际问题。
在不知道数据或环境的情况下,我首先要看的是一些MySQL服务器设置,例如sort_buffer
和key_buffer
。如果您没有更改任何这些,请继续阅读它们。默认设置非常保守,通常可以提升超过默认值的十倍,特别是在你的大铁上。
经过审核后,我会运行查询部分以查看速度和EXPLAIN
所说的内容。索引的效果可能是深刻的,但MySQL有一个“手指和脚趾”的问题,它不能使用每个表多于一个。带过滤的JOIN
可能需要两个。所以它必须下降到行扫描以进行另一次检查。但话说回来,切断查询并尝试不同的组合会告诉你它开始绊脚的地方。
现在您将了解“引爆点”的位置:这是一些原始数据大小的小幅增加,例如需要提取多少,将导致性能大幅下降,因为某些内部结构变得太大了。此时,您可能希望提高临时表的大小。请注意,这种优化是一种黑色艺术。 : - )
然而,还有另一种方法:非规范化。在一个简单的实现中,定期调度的脚本将不时地运行这个昂贵的查询,并将数据戳入一个更接近您想要显示的结构的单独表中。这种方法有多种变体。可以在应用程序中或使用表触发器即时保持最新。在另一个极端,您可以允许您的应用程序偶尔运行昂贵的查询,但缓存结果一段时间。如果很多人会经常调用它,这是最有效的:即使在每秒运行15次的请求上缓存2秒也会显示出明显的改进。
您可以通过运行半打查询来找到生成相同数据的方法,每个查询都会返回一些数据,并对数据进行后处理。您还可以运行原始查询的版本以返回更多数据(这可能会更快,因为它可以减少过滤)并对其进行后处理。我已经多次发现五个更简单,更小的查询可以更快 - 一个数量级,有时两个 - 比一个试图完成所有操作的大查询。
答案 1 :(得分:0)
由于您扫描整个表格,因此没有索引可以帮助您。 随着数据库的增长,查询总是会变慢。
考虑累积统计数据:在每场比赛之后,插入该游戏的行,并在玩家的行中增加计数器,然后你不需要count()和sum()因为信息可用。
答案 2 :(得分:0)
答案 3 :(得分:0)
小改进
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(1 ) 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,
( select * from dotagames dg1 where dg.winner <> 0 ) as dg,
games as ga,
dotaplayers as dp,
scores as sc
where 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
<强>的变化:强> 1. count(*)chnaged to count(1) 2.在FROM中,行数减少。