通过索引搜索,查询数据过程?
回表
给定下面一个表,执行 select * from T where k between 3 and 5
语句,索引树的搜索过程是怎样的?
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'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');
从表构造上看,索引搜索树是这样的:
然后这条 SQL 查询语句的执行流程是这样的:
- 在 k 索引树上找到 k=3 的记录,取得 ID = 300;
- 再到 ID 索引树查到 ID=300 对应的 R3;
- 在 k 索引树取下一个值 k=5,取得 ID=500;
- 再回到 ID 索引树查到 ID=500 对应的 R4;
- 在 k 索引树取下一个值 k=6,不满足条件,循环结束。
在这个过程中,回到主键索引树搜索的过程,我们称为回表。
覆盖索引
假如上述执行的 SQL 语句是这样的呢? select ID from T where k between 3 and 5
这里只需查询 id 的值,而这个值已经在 k 索引树上了,因此可以直接提供查询结果,不需要回表,这样的话成为覆盖索引。
由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
在一个市民信息表上,是否有必要将身份证号和名字建立联合索引?答:正常身份证号是唯一标识,在该字段上做索引就好了。如果有高频请求根据身份证查姓名,则建立该联合索引(不需回表)。
最左前缀原则
像 B+ 树这种索引结构,可以利用索引的“最左前缀”,来定位记录。
如当在一个市民信息表上做了 (name, age) 做了联合索引:
- 当条件查询
where name = '张三'
的时候,索引快速定位。 - 当条件查询
where name like '张 %'
的时候,这时候也能用上这个联合索引,找到第一个符合条件的记录,然后向后遍历,直到不满足条件为止。
显然,最左前缀原则的基础上,当已经有了 (a, b) 这个联合索引后,一般就不需要单独在 a 上建立索引了。(别忘了建立索引还需要考虑空间)
索引下推
MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引内部中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。