B+树索引原理与使用方法论

244 阅读4分钟

MySQL的B+树索引是什么?

在MySQL里,页是存取数据的基本单位。

每一个页,按照主键的大小进行记录的排序,MySQL为页里的记录进行分组,并给出一个页目录,故根据一个主键在页中查找数据只需要动用这个页目录和二分查找法便可以快速找到。

而同一个表的每一个页面,通过双向链表串联起来,保证前一个表的主键小于后一个节点的主键。而这样以来,这些节点又作为B+树的树叶节点。

而树叶节点上面又有B+树的内层节点,他们同样是页面,不过他们存储的内容的作用就是保证查找主键对应的记录时,从根节点向下查找就可以找到。

而这样一颗根据主键能快速找到记录的B+书,在MySQL里,默认为每一个InnoDB存储引擎的表创建了,叫做聚簇索引

而用户可以自己创建索引,叫做二级索引,这个索引同样也是基于B+树的,只是,索引是按照给出的列的值大小进行树化的,而最终会指向主键。所以当利用二级索引查找记录时,会查找此B+树,得到主键,拿到主键后再去聚簇索引中找到真正的记录,这叫回表

二级索引之外,还有联合索引,联合索引中,每一个索引中的记录,都包含了联合索引所指定的列的值,他们是按照顺序进行排序的。

使用索引的场景

全值匹配

搜索条件中的列和索引列一致的话,这种情况就称为全值匹配。

比如有一个联合索引包含两个列,而搜索条件中有这两个的条件,并且都是判断相等。

匹配左边的列

如果不能全值匹配,那么取其中几个值也是可以的。

如,现在有一个联合索引有三个列,那么如果条件中包含最左边的那个列,也是可以的。

而最好条件列表能尽量多的是从左到右连续的列

匹配列前缀

如果有SQL如下:

WHERE name LIKE 'As%';

那么如果name是索引的一部分的话,也是可以的,因为是匹配前缀,由于索引中的排序是字符串从小到大,故这样是可以动用索引的,而如果没有匹配前缀,那么索引也就无效了。

匹配范围值

当条件是范围值,也是可以用到索引的。

但是如果是多个列的条件,则只有联合索引最左边的列的范围查找才能生效。

精确匹配某一列并范围匹配另外一列

对于联合索引,当最左边的列的条件是精确匹配(“=”)时,那么右边的列就可以进行范围查找。

用于排序

由于二级索引中列是按照顺序进行排序的,索引如果SQL中要求排序(必须能和索引中的排序一致),那么就索引就能减去排序的工作。(ORDER BY的子句后边的列的顺序也必须按照索引列的顺序给出),ASC、DESC混用是不可以的。

用于分组

由于索引中本就蕴含了分组的意义。

索引使用的注意点

  1. 只为用于搜索、排序或分组的列创建索引 没有必要进行创建,因为其不是关键的数据。

  2. 为列的基数大的列创建索引 这是离散化导致的,如果一个表中,某列数据重复率非常高(极端情况就是,某列其实只有一个数据),建立索引就没有任何意义。

  3. 索引列的类型尽量小 比较时所花的计算成本会降低

  4. 可以只对字符串值的前缀建立索引 在建立索引的时候,指定字符串列的前几位(这样后几位就不参加比较了,同样减轻了计算负担)

  5. 只有索引列在比较表达式中单独出现才可以适用索引

    WHERE my_col * 2 < 4
    #这样的表达式会影响索引
    
    
  6. 为了尽可能少的让聚簇索引发生页面分裂和记录移位的情况,建议让主键拥有AUTO_INCREMENT属性。 自动递增,可以减少页面移位。

  7. 定位并删除表中的重复和冗余索引 不要让一个列出现在多个索引中。

  8. 尽量使用覆盖索引进行查询,避免回表带来的性能损耗。 覆盖索引是,查询的字段正好都在索引里,这样就不需要回表了~