一、前言
索引的出现就是为了提高数据查询的效率,就像书的目录一样。
二、索引常见数据结构
可以用于提高读写效率的数据结构很多,常见的是哈希表、有序数组、搜索树。
1、哈希表
哈希表时一种key、value存储数据的结构,我们只要输入待查证的值即key,就可以找到其对应的值即value。哈希的思路很简单,把值放在数组里,用一个哈希函数把key换算成确定的值,然后把value放在数组的这个位置。多个key经过hash运算之后,会出现同一个值的情况。处理这种情况的一种方式是拉出链表。所以哈希表这种结构适用于只有等值查询(比如age=18)的场景,比如Memcached及其他一些NoSQL引擎。
2、有序数组
有序数组在等值查询和范围查询的场景中都非常优秀,如果仅仅看查询效率,有序数组就是最好的数据结构了。但是,在更新数据的时候就更麻烦了,你往中间插入一个记录就必须挪动后面所有的记录,成本太高。所以有序索引只适用于静态存储引擎。 比如2017年北京市所有出生人口信息,这类不会在修改的数据。
三、InnoDB的索引模型
在InnoDB中,表都是根据主键顺序以索引的形式存放的,InnoDB使用了B+树索引,所以数据都是存储在B+树中的。
每一个索引对应一个B+树。
假设我们有1个主键列为ID的表,表中有字段K,并且在K上有索引。
这个表的建表语句是:
mysql->create table t(
id int primary key,
k int not null,
name varchar(16),
index(k))engine=InnoDB;
表中R1~R5的(ID,K) 的值分别为(100,1),(200,2),(300,3),(400,4),(500,5),(600,6)。两棵树的示例示意图如下:
从图中可以看出,根据叶子节点的的内容,索引类型分为主键索引和非主键索引。
主键索引的叶子节点存的是整行数据,在InnoDB中,主键索引也被称为聚簇索引。
非主键索引的叶子节点存的是主键的值,在InnoDB中,非主键索引也被称为二级索引。
基于主键索引和普通索引的查询有什么区别?
如果语句是select * from T where ID=500,即主键查询方式,则只需要搜索ID这颗B+树;如果语句是select * from T where K=5,即普通索引查询方式,则需要先索引k索引这棵树。得到ID的值为500,再到ID索引树搜索一次,这个过程称为回表。 也就是说基于非主键索引的查询需要多扫描1颗索引树。因此,我们在应用中,应该尽量使用主键查询。
四、回表和覆盖索引
mysql> create table T(
ID int primary key,
k int NOT NULL DEFAULT 0,
s varchar(16) NOT NULL DEFAULT '',
index k(k))
engine=InnoDB
insert into T values(100,1'aa'),(200,2'bb'),(300,3,'cc'),(400,4,'dd'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg'),(800,8,'hh');
1、回表
在上面这个表T中,如果执行select * from T where k between 3 and 5,需要执行几次树的索引操作,会扫描多少行。

1、在k索引树上找到k=3的记录,取得ID=300;
2、再到ID索引树查到ID=300对应的R3;
3、在k索引树取下一个值k=5,取得ID=500;
4、再回到ID索引树查到ID=500对应的R4;
5、在k索引树取下一个值k=6,不满足条件,结束。
在这个过程中,回到主键索引树搜索的过程,我们称为回表。可以看到,这个查询过程中读了k索引树的三条记录(步骤1、3和5),回表了2次。(步骤2和4)
2、覆盖索引
如果执行的语句是select ID from T where k between 3 and 5。这时只需要查询ID的值,而ID的值已经在K索引树上了。因此可以直接提供查询结果,不需要回表。 也就是说在这个查询里面,索引k已经覆盖了我们的需求,所以我们称为覆盖索引。由于覆盖索引可以减少树的搜索次数,显著提高查询性能,所以使用覆盖索引是1个常用的性能优化手段。
来源:oschina
链接:https://my.oschina.net/u/4312499/blog/4513747