介绍

建立在多列上的索引成为联合索引

比如,将商品表中的 product_no 和 name 字段组合成联合索引 (product_no, name)

CREATE INDEX index_product_no_name ON product(product_no, name);

下图为联合索引(product_no, name)的 B+Tree 示意图(叶子节点画的是单向链表,实际为双向,图片有误):

Untitled

联合索引的非叶子节点用两个字段的值作为 B+Tree 的 key 值。

联合索引查询数据时,先按 product_no 比较,在 product_no 相同的情况下再按 name 列比较。也就是说,联合索引查询的 B+Tree 是先按 product_no 进行排序,然后在 product_no 相同的情况下再按 name 字段排序。

因此,使用联合索引时,存在最左匹配原则:按照最左边字段优先的方式进行索引的匹配,如果不遵守,联合索引就失效。

比如,创建了一个 (a,b,c) 的联合索引,查询条件是以下几种,就可以匹配上联合索引:
- where a=1;
- where a=1 and b=2 and c=3;
- where b=2 and a=1;

需要注意的是,因为有查询优化器,所以 a 字段在 where 子句的顺序并不重要

但是,如果是以下几种,因为不符合 [最左匹配原则],所以无法匹配上联合索引:
- where b=2;
- where c=3;
- where b=2 and c=3;

上面这些**查询条件之所以会失效,是因为(a, b, c) 联合索引,是先按 a 排序,在 a 相同的情况再按 b 排序,在 b 相同的情况再按 c 排序。**
所以,b 和 c 是全局无序,局部相对有序的,这样在没有遵循最左匹配原则的情况下,是无法利用到索引的。

我这里举例联合索引(a, b)的 B+ Tree 如下(叶子节点画的是单向链表,实际为双向,图片有误):

Untitled

可以看到,a 是全局有序的(1, 2, 2, 3, 4, 5, 6, 7 ,8),而 b 是全局是无序的(12,7,8,2,3,8,10,5,2)。因此,直接执行 where b = 2 这种查询条件没有办法利用联合索引的,利用索引的前提是索引里的 key 是有序的

只有在 a 相同的情况下,b 才是有序的,比如 a 等于 2 的时候,b 的值为(7,8),这时就是有序的,这个有序状态是局部的,因此,执行 where a = 2 and b = 7 时 a 和 b 字段能用到联合索引,也就是联合索引生效了。

联合索引范围查询

联合索引有一些特殊情况,并不是查询过程使用了联合索引查询,就代表联合索引中的所有字段都用到了联合索引进行索引查询,可能存在部分字段用到联合索引的 B+Tree,部分字段没有用到的情况,这种特殊情况就发生在范围查询。