【问题标题】:Two single-column indexes vs one two-column index in MySQL?MySQL 中的两个单列索引与一个两列索引?
【发布时间】:2011-01-21 22:21:15
【问题描述】:

我面临以下问题,但我不确定最佳做法是什么。

考虑下表(它会变大):

ID PK | giver_id FK |收件人 ID FK |日期

我正在使用 InnoDB,据我了解,它会自动为两个外键列创建索引。但是,我也会在需要匹配以下特定组合的地方进行大量查询:

SELECT...WHERE giver_id = x AND recipient_id = t.

每个这样的组合在表中都是唯一的。

在这些列上添加两列索引是否有任何好处,或者理论上两个单独的索引是否足够/相同?

【问题讨论】:

  • 如果两列的组合是唯一的,您可以创建一个具有独特功能的两列索引,这不仅可以提高查询速度,还可以增加表的一致性。
  • "MySQL 可以将多列索引用于测试索引中所有列的查询,或者只测试第一列、前两列、前三列等的查询。如果您在索引定义中以正确的顺序指定列,则单个复合索引可以加快同一张表上的多种查询。” - Multiple-Column Indexes
  • 推断@user1585784;如果两列的组合是唯一的,我认为应该为它们使用唯一的键。事实上,如果要在数据库级别强制执行唯一性,唯一键是最简单的方法......

标签: sql mysql database performance indexing


【解决方案1】:

一个覆盖索引,如:

ALTER TABLE your_table ADD INDEX (giver_id, recipient_id);

...表示如果查询引用 giver_idgiver_idrecipient_id 的组合,则可以使用索引。请注意,索引条件是基于最左侧的 - 仅引用 recipient_id 的查询将无法在我提供的语句中使用覆盖索引。

请注意,某些较旧的 MySQL 版本每个 SELECT 只能使用一个索引,因此覆盖索引将是优化查询的最佳方法。

【讨论】:

  • MySQL can only use one index per SELECT 这不再是真的了,如果你编辑你的答案来更新就好了。
  • 能否解释一下为什么recipient_id无法使用覆盖索引?
  • @IvoPereira MySQL 中的多列索引让您可以从左到右使用索引中的所有字段。例如,如果您有一个 INDEX (col1, col2, col3, col4),那么该索引将应用于带有 WHERE 子句的搜索,例如 col1 = 'A'col1 = 'A' AND col2 = 'B'col1 = 'A' AND col2 ='B' AND col3 = 'C' AND col4 = 'D',但此特定索引不会用于像 @987654333 这样的任何内容@ 或 WHERE col3 = 'C' AND col4 = 'D' 因为搜索字段不在索引定义中的最左侧。您必须添加额外的索引来覆盖这些字段。
  • “每个 SELECT 一个索引”,mariadb 10.1 仍然如此吗?
  • @Anthony:不,见上面 Davor 的评论。
【解决方案2】:

要考虑的另一件事是,两种方法的性能特征都将基于数据集的大小和基数。您可能会发现 2 列索引仅在某个数据集大小阈值时才变得注意到性能更高,或者正好相反。没有什么可以替代您的具体场景的性能指标。

【讨论】:

  • 能否请您链接到与此相关的一些文档。谢谢。
【解决方案3】:

如果其中一个外键索引已经非常有选择性,那么数据库引擎应该将那个外键索引用于您指定的查询。大多数数据库引擎使用某种启发式方法来在这种情况下选择最佳索引。如果这两个索引本身都不是高度选择性的,那么添加建立在两个键上的索引可能确实有意义,因为您说您将经常使用这种类型的查询。

另一件要考虑的事情是,您是否可以消除此表中的 PK 字段并在 giver_idrecipient_id 字段上定义主键索引。你说这个组合是独一无二的,所以它可能会起作用(考虑到很多只有你才能回答的其他条件)。不过,通常情况下,我认为增加的复杂性是不值得的。

【讨论】:

  • 谢谢马克,其中一个键确实非常有选择性,所以应该没问题。我选择保留两个(自动)索引并查看它随着时间的推移如何执行。我还考虑了一个组合的给予者:接收者主键,但由于每个字段也需要单独搜索,它只会增加 php 开销。此外,新密钥将是一个(较长的)字符串而不是(较短的)整数。
【解决方案4】:

如果您有两个单列索引,则在您的示例中只使用其中一个。

如果您有一个包含两列的索引,则查询可能会更快(您应该衡量)。两列索引也可以用作单列索引,但仅限于最前面列出的列。

有时在 (A,B) 上有一个索引并在 (B) 上有另一个索引会很有用。这使得使用任一列或两列的查询速度更快,但当然也会占用更多磁盘空间。

在选择索引时,还需要考虑对插入、删除和更新的影响。更多索引 = 更慢的更新。

【讨论】:

  • "MySQL 可以将多列索引用于测试索引中所有列的查询,或者只测试第一列、前两列、前三列等的查询。如果您在索引定义中以正确的顺序指定列,则单个复合索引可以加快同一张表上的多种查询。” - Multiple-Column Indexes
猜你喜欢
  • 2013-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-28
  • 1970-01-01
  • 2013-01-04
  • 1970-01-01
相关资源
最近更新 更多