如何优化这个 MySQL 查询
Posted
技术标签:
【中文标题】如何优化这个 MySQL 查询【英文标题】:How to optimize this MySQL query 【发布时间】:2010-05-27 17:18:02 【问题描述】:这个查询在数据库很小的时候工作得很好,但是现在数据库中有数百万行,我意识到我应该早点考虑优化它。它正在查看超过 600,000 行,并且正在使用 where;使用临时的;使用文件排序(这会导致执行时间为 5-10 秒)。它正在使用字段“battle_type”上的索引。
SELECT username, SUM( outcome ) AS wins, COUNT( * ) - SUM( outcome ) AS losses
FROM tblBattleHistory
WHERE battle_type = '0' && outcome < '2'
GROUP BY username
ORDER BY wins DESC , losses ASC , username ASC
LIMIT 0 , 50
【问题讨论】:
对它运行 EXPLAIN。它会告诉你应该在哪里收紧。 您可以做的一件事是将结果缓存到文件或其他东西,然后每 X 分钟重新缓存一次。 【参考方案1】:看来您需要在username, battle_type, outcome
或username, outcome, battle_type
上建立索引。
【讨论】:
我都尝试了,然后运行 EXPLAIN,但它仍然只是使用 Battle_type 作为索引。知道为什么会这样吗?它也没有将其显示为可能的键。 不同顺序的索引有什么区别? 不幸的是,这两个索引在这里都没有用,因为分组发生在WHERE
条件之后。
@Kerry:通常,您首先指定粒度最大的列,然后指定粒度较小的列。
@Gilbert Le Blanc:再次错过 =),请参阅下面的答案。【参考方案2】:
首先要确保您有良好的索引(正如其他人提到的那样)。
但是,您似乎正在为网页创建某种排行榜。我的第一个问题是——你真的需要实时执行这个查询吗?您能否在数据库中创建一个带有此查询结果的表(或在用户表中添加一个胜利和失败列)并定期刷新它?
【讨论】:
【参考方案3】:让我们看看你在做什么:
-
查找battle_type = 0且结果为
按用户名排序以进行分组
计算聚合并将行折叠到不同的用户名
按动态计算字段排序
在第 3 步和第 4 步中,您没有任何影响。当前形式的第 2 步无法从任何索引中受益,因为 outcome < 2
是范围条件,但 (battle_type, results, username) 上的索引看起来非常诱人。
假设outcome
是0,1,2,3...
的枚举,您可以将范围条件更改为相等比较并受益于(battle_type,结果,用户名)的索引:
SELECT username, SUM( outcome ) AS wins, COUNT( * ) - SUM( outcome ) AS losses
FROM tblBattleHistory
WHERE battle_type = 0 AND outcome IN (0, 1)
GROUP BY username
ORDER BY wins DESC , losses ASC , username ASC
LIMIT 0 , 50
如果outcome
不是枚举,则可以使用 (battle_type, 结果) 上的索引。现在仅 (battle_type) 上的索引是多余的,因为 battle_type
是复合索引中的前缀。
【讨论】:
这对一些人有所帮助,但它仍在查看超过 500,000 行,因此我将创建一个表来缓存结果并每 10 分钟更新一次。以上是关于如何优化这个 MySQL 查询的主要内容,如果未能解决你的问题,请参考以下文章