一、联合索引的作用

联合索引(也称复合索引、组合索引)是指在一个索引中包含多个表中的列。你可以把它想象成一本电话簿,它不是单纯按“姓”或者按“名”排序,而是先按“姓”排序,在“姓”相同的情况下再按“名”排序。

它的主要作用有:

  1. 优化多列查询条件:当你的 WHERE子句中同时使用了索引中的多个列时,联合索引可以极大地提高查询效率。例如,索引是 (last_name, first_name),查询是 WHERE last_name = 'Smith' AND first_name = 'John',这个索引就能精准定位。

  2. 避免回表(Covering Index):如果查询的所有字段都包含在联合索引中(即索引包含了要查询的列和条件列),数据库可以直接从索引中获取所有数据,而无需再回到主表(数据文件)中去查找。这被称为“覆盖索引”,性能提升非常显著。

  3. 优化排序(ORDER BY):如果 ORDER BY子句的顺序与联合索引的创建顺序一致(或相反,但需指定 DESC),数据库可以直接利用索引的有序性来避免额外的排序操作。例如,索引是 (A, B),查询是 ORDER BY A, B或 ORDER BY A DESC, B DESC,就可以利用索引排序。

  4. 优化最左前缀匹配查询:这是联合索引最重要的特性。即使查询没有使用索引中的所有列,只要使用了从最左边开始的连续列,索引仍然可能生效。例如,索引是 (A, B, C)

    • WHERE A = 1(生效)

    • WHERE A = 1 AND B = 2(生效)

    • WHERE A = 1 AND B = 2 AND C = 3(生效)

    • WHERE B = 2不生效,因为跳过了最左边的 A)

    • WHERE A = 1 AND C = 3部分生效,索引只会用到 A 列来筛选,C 列用不上)


二、一个联合索引 vs 三个单独索引的区别

这是问题的关键。我们通过一个具体的例子来说明,假设我们有一个 users表,有三个字段:countrycityage

  • 方案一:一个联合索引idx_combined (country, city, age)

  • 方案二:三个单独索引idx_country (country)idx_city (city)idx_age (age)

区别对比表

特性

一个联合索引 (country, city, age)

三个单独索引 (country)(city)(age)

索引结构

一棵B+树,数据按 (country, city, age) 的顺序排序。

三棵独立的B+树,分别按 country、city、age 排序。

存储空间

较小。只有一个索引,占用空间少。

较大。有三个索引,占用空间约是联合索引的3倍。

写入性能

较好。插入、更新、删除数据时,只需要维护一个索引。

较差。需要维护三个索引,写操作开销更大。

查询场景1:等值查询
WHERE country='CN' AND city='BJ' AND age=25

效率极高。可以利用索引的精确定位,快速找到数据。是联合索引的最佳使用场景。

数据库优化器通常只能选择一个它认为最优的索引(比如 idx_country),然后用这个索引筛出一批数据,再回到数据表中用 city和 age条件进行过滤。效率远低于联合索引。

查询场景2:最左前缀查询
WHERE country='CN'
WHERE country='CN' AND city='BJ'

效率高。完全符合最左前缀原则,索引完全有效。

对于 WHERE country='CN',使用 idx_country效率与联合索引相当。对于 WHERE country='CN' AND city='BJ',情况与场景1类似,效率不如联合索引。

查询场景3:非最左前缀查询
WHERE city='BJ'
WHERE age=25
WHERE city='BJ' AND age=25

索引失效。因为跳过了最左边的 country列,无法使用索引的有序性,会导致全表扫描。

可以生效。对于 WHERE city='BJ',可以使用 idx_city;对于 WHERE age=25,可以使用 idx_age。在这种场景下,单独索引的优势明显。

排序优化
ORDER BY country, city, age

效率高。可以直接利用索引的有序性,无需额外排序。

效率低。数据库需要将数据取出后进行额外的排序操作(Using filesort),如果数据量大,会非常慢。


三、如何选择?实践建议

没有绝对的优劣,关键在于你的查询模式

应该优先使用联合索引的情况:

  • 你的查询条件经常同时使用多个字段进行过滤(特别是等值查询)。

  • 你需要对多个字段进行排序,并且排序顺序与索引顺序一致。

  • 你希望实现覆盖索引,避免回表,追求极致查询性能。

例如:你的业务中大部分查询都是 WHERE country='XX' AND city='XX',那么建立 (country, city)的联合索引是最佳选择。

考虑使用多个单独索引的情况:

  • 你的查询条件变化多端,且经常单独使用各个字段作为条件。

  • 某个字段的选择性非常高(几乎唯一),为其建立单独索引的价值很大。

例如:你的业务中,有的查询只用 country,有的查询只用 city,有的查询只用 age,很少有组合查询。那么建立三个单独索引可能更合适。

更高级的策略:混合使用

在实际生产中,通常会采用混合策略,根据最频繁、最耗时的查询来设计索引。

  • 为最核心的联合查询建立联合索引:比如为 (country, city, age)建立一个索引。

  • 为高频的单列查询建立单独索引:如果 city 的单查也非常多,可以再单独为 city建立一个索引。但这会增加存储和写入开销,需要权衡。

总结一下核心原则:

  1. 高选择性的列放在联合索引的左边(即区分度高的列,如用户ID,放在区分度低的列,如性别,前面)。

  2. 遵循最左前缀原则 来设计索引顺序,以满足你的核心查询场景。

  3. 权衡读写比例 索引越多,写操作越慢。对于写密集型的表,要谨慎添加索引。

  4. 使用 EXPLAIN 分析你的SQL语句,确认索引是否被正确使用。这是最重要的优化工具。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐