多个和单个索引

Posted

技术标签:

【中文标题】多个和单个索引【英文标题】:Multiple and single indexes 【发布时间】:2011-01-10 11:17:33 【问题描述】:

自从我使用 mysql 多年以来,我有点不好意思问这个问题,但是哦。

我有一个包含两个字段的表,ab。我将对其运行以下查询:

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 = 1b = 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 子句使用复合索引。

【讨论】:

以上是关于多个和单个索引的主要内容,如果未能解决你的问题,请参考以下文章

单个索引与多个字段索引

单个节点的多个 Elasticsearch 索引

在 Postgres 的单个索引中包含多个列

Python pandas - 将具有多个日期索引的csv合并到单个日期索引

通过将单个查询图像与多个图像的列表匹配来存储关键点索引

如何匹配并返回字符串的多个实例,其中单个撇号可以包含在任何索引中?