MySQL索引实现和优化(一)

1、什么是索引?

索引之于数据库,就好像目录之于书本。使用索引是为了提高数据查询的效率。在MySQL中,使用主键索引,可以快速定位到数据库表中的对应行。

2、实现索引的方式(数据结构)

①哈希表:是一种以键值(key-value)对存储的数据结构,输入一个key,通过哈希函数,可以确定一个位置,得到这个位置对应的value。缺点是,当多个key通过哈希运算确定的是哈希表中同一个位置,那么将发生冲突。一种解决办法是采用"拉链法",即将所有冲突对象用链表相连。一般来说,这个链表是采用头插或者尾插的方式增加对象的对象,因此链表上的对象一般不是有序的。那么,如果在这种情况下进行范围查询,速度会很慢,因为对于范围查询中的每一个值,都要全部扫描一遍。所以哈希表只适合于等值查询。

②有序数组:这种类型的索引适合等值和范围查询,缺点是当进行插入或者删除记录的时候,需要挪动大量元素。因此,有序数组索引只适合静态存储索引,即存储的记录基本不会发生增删。

③搜索树:使用二叉平衡树,搜索一个节点的时间复杂度为O(logn),为了保持树的平衡性,更新的时间复杂度为O(logn)。虽然平衡二叉树的搜索效率最高,但是实际中并不使用二叉树,因为索引是要写到磁盘上的,也要从磁盘读。记录数相同的情况下,二叉搜索树与N叉搜索树相比(N>2),二叉树的树高更大,那么一次查询可能需要访问的数据块就更多,即IO次数更多,查询更慢。MySQL中使用B+树作为索引数据结构。

3、为什么MySQL使用B+树作为索引数据结构而不是B树?

因为B+树中间节点不存储信息(B树的中间节点存储信息),数据都存储在叶子节点,所以同样大小的数据块可以容纳更多的索引,查询时磁盘访问次数就更少。

4、InnoDB两种索引

InnoDB中索引类型分为主键索引普通索引。主键索引的叶子节点存储的是与主键对应的整行记录,普通索引的叶子节点存储的是对应主键的值。因此如果使用普通索引查找一行记录,则需要进行"回表操作",即先从普通索引树中查找到主键值,再在主键索引树中找到对应行。

主键的长度越小,普通索引的叶子节点就越小,普通索引占用的空间就越小,这也是推荐用自增主键的原因之一。另一个原因是使用自增主键时,每次插入新记录都是追加操作,不涉及移动其他记录,也不会触发叶子节点的分裂。

5、索引优化

如果使用普通索引查找记录,很多情况下可能需要做"回表"操作。因此,可以想到的优化方式是避免"回表"。

①使用覆盖索引。即直接在普通索引上就可以拿到想要查询的信息,而不用二次索引。比如,如果有一个高频请求,要根据市民的身份证号查询其姓名,那么我们可以建立一个"身份证号、姓名"联合索引,首先通过身份证号定位到索引树的具体位置,再从该位置上获取到对应姓名。

②最左前缀原则。最左前缀可以是联合索引的最左N个字段,也可以是字符串索引的最左M个字符,使用这些最左前缀可以定位到所有包含这些前缀的索引。例如,有一个"name age"的联合索引,如果要查所有姓张的人,那么语句where name like ‘张%’是可以使用到这个联合索引的。

基于最左前缀原则,可以对联合索引进行优化,即如何调整索引内的字段顺序。调整的目标是,可以少维护一个索引。例如,对于name和age的联合索引,如果一般需要通过name查询age,也有只查询name、不查询age的情况,则索引内字段顺序为"name age"。但是如果有只查询age的情况,则"name age"的索引将不能使用,需要单独建age的索引。

③索引下推。对于不符合最左前缀原则的查询,比如对于"name age"的联合索引,查询语句是where name like ‘周%’ and age =10,那么在索引的遍历过程中,就会对索引中已包含的字段作判断,删除掉不满足条件的记录,减少回表次数。因此,对于每个查询到的姓张的联合索引,如果age=10,则回表查询,如果age!=10,则放弃回表。

猜你喜欢

转载自blog.csdn.net/Longstar_L/article/details/107217238
今日推荐