多个和单个索引
Posted
技术标签:
【中文标题】多个和单个索引【英文标题】:Multiple and single indexes 【发布时间】:2011-01-10 11:17:33 【问题描述】:自从我使用 mysql 多年以来,我有点不好意思问这个问题,但是哦。
我有一个包含两个字段的表,a
和 b
。我将对其运行以下查询:
SELECT * FROM ... WHERE A = 1;
SELECT * FROM ... WHERE B = 1;
SELECT * FROM ... WHERE A = 1 AND B = 1;
从性能的角度来看,以下索引配置中的至少一种是否至少对至少一个查询较慢?如果是,请详细说明。
ALTER TABLE ... ADD INDEX (a); ALTER TABLE ... ADD INDEX (b);
ALTER TABLE ... ADD INDEX (a, b);
ALTER TABLE ... ADD INDEX (a); ALTER TABLE ... ADD INDEX (b); ALTER TABLE ... ADD INDEX (a, b);
谢谢(注意我们说的是非唯一索引)
【问题讨论】:
【参考方案1】:是的,至少有一种情况要慢得多。如果只定义以下索引:
ALTER TABLE ... ADD INDEX (a, b);
...那么查询SELECT * FROM ... WHERE B = 1;
将不会使用该索引。
当您使用复合键创建索引时,键的列顺序很重要。建议尝试对 key 中的列进行排序以增强选择性,将最具选择性的列放在 key 的最左侧。如果您不这样做,并将非选择性列作为键的第一部分,则可能根本不使用索引。 (来源:Tips on Optimizing SQL Server Composite Index)
【讨论】:
配置 #3 而不是 #1 有什么优势吗? 是的,可能会有优势。当查询中的所有数据都保存在索引本身中时,复合索引可能会成为覆盖索引。一般来说,SELECT A, B FROM ... WHERE A = 1;
使用(A, B)
上的复合索引会更快,因为查询不需要从表中获取任何数据。数据已在索引中。
请记住,索引会占用空间,并且可能会影响插入和更新的一些性能。仅当您的应用程序将执行证明额外索引合理的查询时,我才会选择选项 3...关于覆盖索引的提示:sql-server-performance.com/tips/covering_indexes_p1.aspx
@Daniel:是的,但是即使(A, B)
不是查询的覆盖索引,当单个索引返回的两个集合很大时,它也会快很多,作为一个巨大的集合联合操作有时可能比全表扫描更昂贵。
@Henning:好点。选择a = 1 and b = 1
时,即使索引不是覆盖索引,选项3也会更快。【参考方案2】:
仅仅存在一个索引就不可能减慢SELECT
查询:它只是不会被使用。
理论上,优化器可能会错误地在(a, b)
上选择更长的索引,而不是在(a)
上选择更长的索引来服务仅搜索a
的查询。
在实践中,我从未见过:MySQL
通常会犯相反的错误,即在存在较长索引时采用较短的索引。
更新:
在您的情况下,以下任一配置都足以满足所有查询:
(a, b); (b)
或
(b, a); (a)
MySQL
也可以使用两个单独的索引和index_intersect
,所以创建这些索引
(a); (b)
也将使用a = 1 AND b = 1
加快查询速度,但程度低于上述任何解决方案。
您可能还想在我的博客中阅读这篇文章:
Creating indexes更新 2:
看来我终于明白你的问题了:)
ALTER TABLE ... ADD INDEX (a); ALTER TABLE ... ADD INDEX (b);
非常适合a = 1
和b = 1
,相当适合a = 1 AND b = 1
ALTER TABLE ... ADD INDEX (a, b);
对于a = 1 AND b = 1
非常好,对于a = 1
几乎非常好,对于b = 1
很差
ALTER TABLE ... ADD INDEX (a); ALTER TABLE ... ADD INDEX (b); ALTER TABLE ... ADD INDEX (a, b);
非常适合所有三个查询。
【讨论】:
嗯,是的,但是为什么要添加不必要的索引呢? 我认为您误解了 OP。我以为他在问“其中一个比其他慢吗?”不是“其中之一比没有索引慢吗?”【参考方案3】:SQL 将选择最能覆盖查询的索引。 A、B 上的索引将涵盖情况 1 和 3 的查询,但不会涵盖情况 2(因为主索引列是 A)
所以要覆盖所有三个查询,您需要两个索引:
ALTER TABLE ... ADD INDEX (a, b); ALTER TABLE ... ADD INDEX (b)
【讨论】:
【参考方案4】:对于示例,您的索引集 #3 是最佳的。 Mysql 会为单列 where 子句选择单个 A 和 B 索引,并为 A & B where 子句使用复合索引。
【讨论】:
以上是关于多个和单个索引的主要内容,如果未能解决你的问题,请参考以下文章