2010-02-28 165 views
65

我面临以下问题,我不确定最佳做法。MySQL中的两个单列索引与一个两列索引?

考虑下表(它会变大):

id PK | giver_id FK | recipient_id FK | date

我使用InnoDB,据我所知,它为两个外键列自动创建索引。不过,我也会做很多的查询,我需要匹配一个特定的组合:

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

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

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

回答

76

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

如果您有两列的索引,查询可能会更快(您应该测量)。双列索引也可以用作单列索引,但仅限列出的列。

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

选择索引时,还需要考虑插入,删除和更新的效果。更多索引=更新较慢。

21

覆盖索引,如:

ALTER TABLE your_table ADD INDEX (giver_id, recipient_id); 

...将意味着如果查询简称giver_id,或giver_idrecipient_id组合索引都可以使用。请注意,索引标准是最基础的 - 仅提及recipient_id的查询将无法在我提供的声明中使用覆盖索引。

此外,MySQL每个SELECT只能使用一个索引,因此覆盖索引是优化查询的最佳方式。

+4

'MySQL只能使用每个SELECT一个索引'这不再是真的,如果您编辑了要更新的答案,那将会很好。 – Davor 2015-09-22 21:25:42

+0

你是否介意解释为什么覆盖索引不能被'recipient_id'使用? – 2015-10-05 15:50:50

+2

@IvoPereira MySQL中的多列索引使您可以使用索引中的所有字段,从左到右。例如,如果你有一个'INDEX(col1,col2,col3,col4)',那么这个索引将用于'WHERE'子句的搜索,比如'col1 ='A''或'col1 ='A'AND col2 = 'B'或'col1 ='A'和col2 ='B'和col3 ='C'和col4 ='D',但这个特定的索引不会用于像'WHERE col2 ='B' '或'WHERE col3 ='C'和col4 ='D',因为搜索字段在索引定义中不是最多的。您将不得不添加额外的索引来覆盖这些字段。 – Slicktrick 2017-02-15 17:43:14

3

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

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

+0

谢谢马克,其中一个键确实非常有选择性,所以它应该没问题。我选择保留这两个(自动)索引,并查看它随着时间的推移如何执行。我也想过一个联合的提供者:接收者主键,但是每个字段也需要单独搜索,它只会增加php的开销。此外,新密钥将是(更长)字符串,而不是(更短)整数。 – Tom 2010-02-28 04:35:27

0

要考虑的另一件事是两种方法的性能特征将基于数据集的大小和基数。您可能会发现,2列索引仅在某个数据集大小阈值时才会注意到性能更高,或者恰恰相反。没有任何东西可以替代您确切场景的性能指标。