Mysql联合索引的最左前缀原则以及b+tree

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql联合索引的最左前缀原则以及b+tree相关的知识,希望对你有一定的参考价值。

参考技术A        覆盖索引,这一点是最重要的,重所周知非主键索引会先查到主键索引的值再从主键索引上拿到想要的值,这样多一次查询索引下推。但是覆盖索引可以直接在非主键索引上拿到相应的值,减少一次查询。

        在一张大表中 如果有 (a,b,c)联合索引就等于同时加上了 (a) (ab) (abc) 三个索引 减少了存储上的一部分的开销和操作开销

        梯度漏斗,比如 select *from t where a = 1 and b = 2 and c = 3; 就等于在满足 a = 1 的一部分数据中过滤掉b = 2 的 再从 a = 1 and b = 2 过滤掉 c = 3 的,越多查询越高效。

    即最左优先,在检索数据时从联合索引的最左边开始匹配,类似于给(a,b,c)这三个字段加上联合索引就等于同时加上了 (a) (ab) (abc) 这三种组合的查询优化

    举个栗子:

CREATE TABLE `user`  (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `name` varchar(25),

  `sex` varchar(25) ,

  `city` varchar(25) ,

  PRIMARY KEY (`id`) USING BTREE,

  INDEX `name`(`name`, `sex`, `city`) USING BTREE

)

EXPLAIN select *from`user` where sex='';

这样是无法触发联合索引的,因为不符合最左原则,没有命中(a) (ab) (abc) 这种组合

+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                    |+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+|  1 | SIMPLE      | user  | NULL      | index | NULL          | name | 309    | NULL |    3 |    33.33 | Using where; Using index |+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+1 rowinset (0.02 sec)

   另外使用执行计划一定要看结果,只有possible_keys有值的情况下才是命中索引

    查询条件要符合最左原则才能使用到索引

    注意: where条件的顺序是否会影响索引的命中,就是本来(ab)的组合,故意写where语句时写成(ba),答案是没有影响,只要遵循了索引的最左原则即可,至少在mysql5.7测试没有问题。

    最后,谈谈索引的底层数据结构b+tree

    我们知道BTREE 每个节点都是一个二元数组: [key, data],所有节点都可以存储数据。key为索引key,data为除key之外的数据。

    查找算法:首先从根节点进行二分查找,如果找到则返回对应节点的data,否则对相应区间的指针指向的节点递归进行查找,直到找到节点或未找到节点返回空指针

    B+Tree有以下不同点:非叶子节点不存储data,只存储索引key;只有叶子节点才存储data,而Mysql中B+Tree:在经典B+Tree的基础上进行了优化,增加了顺序访问指针。在B+Tree的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree。这样就提高了区间访问性能:请见下图,如果要查询key为从18到49的所有数据记录,当找到18后,只需顺着节点和指针顺序遍历即可

依据来源(官网的文档 ):https://dev.mysql.com/doc/refman/5.7/en/multiple-column-indexes.html

MySQL技术专题(10)联合索引的最左匹配原则

参考技术A 如果有一个3列索引(col1,col2,col3),实际上已经建立了三个联合索引(col1)、(col1,col2)、(col1,col2,col3)。

解释

1、b+树的数据项是复合的数据结构,比如(name,age,sex)的时候,b+树是按照从左到右的顺序来建立搜索树的,比如当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道第一步该查哪个节点,因为建立搜索树的时候name就是第一个比较因子,必须要先根据name来搜索才能知道下一步去哪里查询。

2、比如当(张三,F)这样的数据来检索时,b+树可以用name来指定搜索方向,但下一个字段age的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是F的数据了, 这个是非常重要的性质,即索引的最左匹配特性。(这种情况无法用到联合索引)

mysql里创建联合索引的意义

一个顶三个

建了一个(a,b,c)的复合索引,那么实际等于建了(a),(a,b),(a,b,c)三个索引,因为每多一个索引,都会增加写操作的开销和磁盘空间的开销。对于大量数据的表,这可是不小的开销!

覆盖索引

同样的有复合索引(a,b,c),如果有如下的sql: select a,b,c from table where a=1 and b = 1。那么MySQL可以直接通过遍历索引取得数据,而无需回表,这减少了很多的随机io操作。减少io操作,特别的随机io其实是dba主要的优化策略。所以,在真正的实际应用中,覆盖索引是主要的提升性能的优化手段之一

索引列越多,通过索引筛选出的数据越少

有1000W条数据的表,有如下sql:select * from table where a = 1 and b =2 and c = 3,假设假设每个条件可以筛选出10%的数据,如果只有单值索引,那么通过该索引能筛选出1000W*10%=100w 条数据,然后再回表从100w条数据中找到符合b=2 and c= 3的数据,然后再排序,再分页;如果是复合索引,通过索引筛选出1000w *10% *10% *10%=1w,然后再排序、分页,哪个更高效,一眼便知

创建联合索引时列的选择原则

经常用的列优先(最左匹配原则)

离散度高的列优先(离散度高原则)

宽度小的列优先(最少空间原则)

列的离散性计算:count(distinct col)/ count(col)

例如:

id列一共9列都不重复 9/9 = 1

性别列一共9列只有(男或者女)两列 2/9 约等于0.2

离散性越高选择性越大

mysql 最左匹配 联合索引

以上是关于Mysql联合索引的最左前缀原则以及b+tree的主要内容,如果未能解决你的问题,请参考以下文章

联合索引的最左前缀匹配原则

Mysql联合索引最左匹配原则

深入浅析Mysql联合索引最左匹配原则

Mysql中联合索引的最左匹配原则(百度)

索引的最左前缀原则

简述mysql最左原则