在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表。InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的。每一个索引在 InnoDB 里面对应一棵 B+ 树。
主键查询只需要搜索主键这棵 B+ 树;
普通索引查询方式,则需要先搜索索引树,得到主键值,再到主键索引树搜索一次。这个过程称为回表。
如果只需要查 主键ID 的值,而 ID 的值已经在 k 索引树上了,因此可以直接提供查询结果,不需要回表。也就是说,在这个查询里面,索引 已经“覆盖了”我们的查询需求,称为覆盖索引。由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
把高频查询字段设置为联合索引,它可以在这个高频请求上用到覆盖索引,不再需要回表查整行记录,减少语句的执行时间。
索引项是按照索引定义里面出现的字段顺序排序的。因为可以支持最左前缀,所以当已经有了 (a,b) 这个联合索引后,一般就不需要单独在 a 上建立索引了。因此,第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。
以联合索引(A, B)为例。如果现在有一个需求:检索出表中”列A是张开头,而且列B是2的所有数据”。那么,SQL 语句是这么写的:
select * from T whete A like '张%' and B = 2;
在 MySQL 5.6 之前,只能找到所有符合A like '张%'的索引开始一个个回表。到主键索引上找出数据行,再对比字段值。MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断(即判断B = 2是否为true),直接过滤掉不满足条件的记录,减少回表次数。