mysql组合索引

定义

不同于对某列建立索引,可以同时对多个列建立索引,也称复合索引、联合索引。

测试表

CREATE TABLE `test` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `c1` int(10) NOT NULL COMMENT 'c1',
  `c2` int(10) NOT NULL COMMENT 'c2',
  `c3` int(10) NOT NULL COMMENT 'c3',
  `c4` int(10) NOT NULL COMMENT 'c4',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `IDX_C1C2C3` (`c1`,`c2`,`c3`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

其中对c1、c2、c3建立组合索引。

存储结构

单索引的存储结构很好理解,非叶子节点中存储单索引的值。当有多个列组成组合索引时,存储结构如图,摘自《高性能Mysql,第三版》
摘自高性能mysql
组合索引对多个值进行排序是依照定义时索引的的顺序。这里按照c1、c2、c3的顺序定义,即在存储时先按照c1排序,c1相同时按c2进行排序,c2相同时按c3排序。所以查询时想使索引中的c2列生效,那么条件中也要有c1。想使c3列生效,c1和c2必须也要有。这也就是常说的组合索引最左前缀匹配

测试

  • 全匹配
EXPLAIN SELECT  * FROM test WHERE c1 = 111 and c2 = 222 and c3 = 333

在这里插入图片描述
key_len为12,正好为三个字段的长度,证明三个字段的索引全部生效了。
where后的查询顺序不影响组合索引的使用

EXPLAIN SELECT  * FROM test WHERE c2 = 222 and c1 = 111 and c3 = 333

只要包含了需要的索引,explain的结果和上面的一样,不再贴出。

  • 不含c1
EXPLAIN SELECT  * FROM test WHERE c2 = 222 and c3 = 333;

在这里插入图片描述
搜索条件不含c1,发现走的全表扫描,组合索引没有生效。

  • 不含c2
EXPLAIN SELECT  * FROM test WHERE c1 = 111 and c3 = 333

在这里插入图片描述
虽然用到了联合索引,但是实际使用长度只有4,也就是只用了c1。

  • 不含c3
EXPLAIN SELECT  * FROM test WHERE c1 = 111 and c2 = 222

在这里插入图片描述
使用了联合索引,实际使用长度为8,c1和c2都用上了。

  • 匹配列
    这里把c2改成varchar(10)
EXPLAIN SELECT  * FROM test WHERE c1 = 111 and c2 LIKE '22' and c3 = 333

在这里插入图片描述
key_len为40,c1、c2、c3全部使用了。

EXPLAIN SELECT  * FROM test WHERE c1 = 111 and c2 LIKE '%22' and c3 = 333

在这里插入图片描述
key_len为4,只用到了c1。结合组合索引的存储也可以理解,匹配前缀的时候,可以用到排序,但是匹配后缀,排序就失效了,所以从c2这里就断掉了。

  • 匹配范围值
EXPLAIN SELECT  * FROM test WHERE c1 = 111 and c2 < 22 and c3 = 33

在这里插入图片描述
key_len为8,c1和c2生效,范围搜索后的c3失效了。

  • 其他失效情况
EXPLAIN SELECT  * FROM test WHERE c1  = 111 and c2 + 2 = 22 and c3 = 33

在这里插入图片描述
计算式会使该列索引失效,这里只有c1生效了。

EXPLAIN SELECT  * FROM test WHERE c1  = 111 and c2 != 22 and c3 = 33

在这里插入图片描述
!=使得整个组合索引失效。

再次将c2改为varchar(10)

EXPLAIN SELECT  * FROM test WHERE c1  = 111 and c2 not like '22' and c3 = 33

在这里插入图片描述
只有c1生效了。

EXPLAIN SELECT  * FROM test WHERE c1  = 111 and UPPER(c2) = '222' and c3 = 33

在这里插入图片描述
只有c1生效了。

参考

  1. 《高性能mysql,第三版》
  2. http://blog.codinglabs.org/articles/theory-of-mysql-index.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章