分组依据/排序依据的 MySQL 索引
Posted
技术标签:
【中文标题】分组依据/排序依据的 MySQL 索引【英文标题】:MySQL Index for Group By / Order By 【发布时间】:2011-09-19 18:09:35 【问题描述】:请参阅下面的查询。我应该在表上创建什么索引,以便查询将使用索引并避免使用临时和文件排序?我尝试了许多不同的索引组合并阅读了advice here,但我似乎无法弄清楚。我的解释要么是 Using Where
(无索引),要么是 Using Where Using Temporary, Using Filesort
这是一个简化的查询。所有列都是整数。
SELECT c1, Sum(c2)
FROM table
WHERE c3 IS NOT NULL
AND c4 = 2011
AND c5 = 0
AND c6 In (6,9,11)
GROUP BY c1
【问题讨论】:
请记住,mysql 每个表只能使用一个索引,因此如果您在列上放置索引以优化 GROUP BY,您可能最终会伤害自己,因为 WHERE 子句未优化最终还需要做更多的工作(即全表扫描)。 我明白了,但是有没有办法创建一个可以同时被 GROUP BY 和 WHERE 子句使用的索引? 【参考方案1】:这应该对您有所帮助。按如下方式重写您的查询:
SELECT c1, Sum(c2)
FROM table
WHERE c4 = 2011
AND c5 = 0
AND c6 In (6,9,11)
AND c3 IS NOT NULL
GROUP BY c1
现在在列 (c4, c5, c6) 上创建一个复合索引,列按该顺序排列。索引中的列应与 WHERE 子句中的列以相同的顺序出现。否则索引将不起作用。这个索引的选择性足够窄,临时表(分组依据)上的文件排序应该很快。
将 c3 移到查询末尾的原因如下。例如,让我们假设 c3 可以取 0 到 100 之间的值(或者它可以是 NULL)。如果运行“IS NOT NULL”查询,那么 Mysql 需要遍历几乎所有的 B-Tree 索引,除了对应于 NULL 的边。因此,MySQL 认为全表扫描比遍历索引中的所有不同路径更容易。另一方面,您会看到如果您的查询是“IS NULL”并且您的索引是 (c3, c4, c5, c6),那么 Mysql 实际上会使用这个索引。这是因为这种情况下Mysql只需要遍历索引树中NULL值对应的部分即可。
MySQL 需要的索引类型在很大程度上取决于相关查询。正如@louis 建议的那样,在所有列上创建索引不是一个好主意!
【讨论】:
感谢详细的解释! "索引中的列应该与 WHERE 子句中的列以相同的顺序出现。否则索引将不起作用。"查询优化器不关心WHERE
子句的排序方式。 SELECT ... FROM foo WHERE bar = 1 AND baz < 5
将具有与SELECT ... FROM foo WHERE baz < 5 AND bar = 1
完全相同的执行计划,并以完全相同的方式使用索引。条件的类型(相等或不等,选择性或非选择性)是重要的,而不是它出现在 WHERE
子句中的位置。
我不确定这是不是真的。根据我的经验,索引定义的顺序很重要,但 where 子句的顺序并不重要。
同意 Shane N - 优化器会在执行前自动为您重新排序
此外,MySQL 将使用复合索引中的列,直到达到范围条件(=、、IN()、IS NULL、IS NOT NULL、>、=、 和 LIKE 之间)。那么该列将是索引中最后遇到的列。因此,正如 srivani 建议的那样,将其放在索引中的最右边很重要。【参考方案2】:
我认为问题出在“ORDER BY 2 DESC”子句上。即使 c2 被索引 SUM(C2) 也不是。
至于你“应该”拥有哪些索引,这取决于数据,所以我无法评论。
【讨论】:
为了争论,假设我没有使用 ORDER BY 子句。 (我已将其从问题中删除)。我仍然找不到可以工作的索引。【参考方案3】:根据经验,我应该说:为“where”子句中的所有列构建索引(但这里不是 c6)
至少,c4 和 c5。
“分组依据”子句将对结果进行排序。如果结果中有很多记录,索引 c1 也可能有用。
c3 仅被测试为“非空”。但是索引它也可以改善事情,这个有待测试。
Hopz 这很有帮助。
【讨论】:
以上是关于分组依据/排序依据的 MySQL 索引的主要内容,如果未能解决你的问题,请参考以下文章