如何优化这个 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, outcomeusername, outcome, battle_type 上建立索引。

【讨论】:

我都尝试了,然后运行 ​​EXPLAIN,但它仍然只是使用 Battle_type 作为索引。知道为什么会这样吗?它也没有将其显示为可能的键。 不同顺序的索引有什么区别? 不幸的是,这两个索引在这里都没有用,因为分组发生在 WHERE 条件之后。 @Kerry:通常,您首先指定粒度最大的列,然后指定粒度较小的列。 @Gilbert Le Blanc:再次错过 =),请参阅下面的答案。【参考方案2】:

首先要确保您有良好的索引(正如其他人提到的那样)。

但是,您似乎正在为网页创建某种排行榜。我的第一个问题是——你真的需要实时执行这个查询吗?您能否在数据库中创建一个带有此查询结果的表(或在用户表中添加一个胜利和失败列)并定期刷新它?

【讨论】:

【参考方案3】:

让我们看看你在做什么:

    查找battle_type = 0且结果为 按用户名排序以进行分组 计算聚合并将行折叠到不同的用户名 按动态计算字段排序

在第 3 步和第 4 步中,您没有任何影响。当前形式的第 2 步无法从任何索引中受益,因为 outcome &lt; 2 是范围条件,但 (battle_type, results, username) 上的索引看起来非常诱人。

假设outcome0,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 查询的主要内容,如果未能解决你的问题,请参考以下文章

如何优化这个 MySQL 查询

如何索引 - 优化这个 MySQL 查询?

我如何在mysql中优化这个查询?

如何优化这个 mysql 查询 - 解释包括的输出

如何优化Mysql千万级快速分页

如何优化这个非常慢的 MySQL 查询?