索引的分类

  • 聚簇索引主键索引):每个表有且一定会有一个聚簇索引,整个表的数据存储在聚簇索引中,MySQL 索引是采用 B+树结构保存在文件中,叶子节点存储主键的值以及对应记录的数据,非叶子节点不存储记录的数据,只存储主键的值。当表中未指定主键时,MySQL 内部会自动给每条记录添加一个隐藏的 rowid 字段(默认 4 个字节)作为主键,用 rowid 构建聚簇索引。
  • 非聚簇索引辅助索引):也是 B+树结构,不过有一点和聚簇索引不同,非聚簇索引叶子节点存储字段(索引字段)的值以及对应记录主键的值,其他节点只存储字段的值(索引字段)。

MySQL 中非聚簇索引分为:

  • 单列索引:即一个索引只包含一个列。
#格式
create index 索引名称 on 表名(列名)
#例子
create index idx_name on employees(name )
  • 唯一索引:索引列的值必须唯一,允许有一个空值。比普通索引的性能要好。
#格式
create unique index 索引名称 on 表名(列名)
#例子
create unique index idx_unique_name on employees( name)
  • 联合索引组合索引):一次性为表中的多个字段一起创建索引,最左前缀法则 (如何命中联合索引中的索引列)。
    • 注意:一个联合索引建议不要超过 5 个列
#格式
create index 索引名称 on 表(列1 ,列2 ,列3)
#例子
create index idx_name_age_position on employees(name ,age , position)
  • 全文索引 进行查询的时候,数据源可能来自于不同的字段或者不同的表。比如去百度中查询数据,千锋教育,来自于网页的标题或者网页的内容。MyISAM 存储引擎支持全文索引。在实际生产环境中,并不会使用 MySQL 提供的 MyISAM 存储引擎的全文索引功能来是实现全文查找。而是会使用第三方的搜索引擎中间件比如 ElasticSearch (多) 、Solr。

最左匹配原则

在组合索引树中,最底层的叶子节点按照第一列 a 列从左到右递增排列,但是 b 列和 c 列是无序的,b 列只有在 a 列值相等的情况下小范围内递增有序,而 c 列只能在 a,b 两列相等的情况下小范围内递增有序。

B+树会先比较 a 列来确定下一步应该搜索的方向,往左还是往右。如果 a 列相同再比较 b 列。但是如果查询条件没有 a 列,B+树就不知道第一步应该从哪个节点查起。

创建的 idx_abc(a,b,c) 索引,相当于创建了 (a)(a, b)(a,b,c) 三个索引。

组合索引的最左前缀匹配原则:使用组合索引查询时,MySQL 会一直向右匹配直至遇到范围查询(>、<)就停止匹配。

覆盖索引

覆盖索引指的是在一次查询中,如果一个索引包含或者说覆盖所有需要查询的字段的值,我们就称之为覆盖索引,而不再需要回表查询。而要确定一个查询是否是覆盖索引,我们只需要 explain sql 语句看 Extra 的结果是否是 Using index 即可。

覆盖索引是一种很常用的优化手段。因为在使用辅助索引的时候,我们只可以拿到主键值,相当于获取数据还需要再根据主键查询主键索引再获取到数据。但是试想下这么一种情况,在上面 abc_innodb 表中的组合索引查询时,如果我只需要 abc 字段的,那是不是意味着我们查询到组合索引的叶子节点就可以直接返回了,而不需要回表。这种情况就是覆盖索引。

回表

在 InnoDB 的存储引擎中,使用辅助索引查询的时候,因为辅助索引叶子节点保存的数据不是当前记录的数据而是当前记录的主键索引,索引如果需要获取当前记录完整数据就必然需要根据主键值从主键索引继续查询。这个过程我们称为回表,回表必然是会消耗性能影响性能。

如果在一个场景下,select id,name,sex from user where name ='zhangsan'; 这个语句在业务上频繁使用到,而 user 表的其他字段使用频率远低于它,在这种情况下,如果我们在建立 name 字段的索引的时候,不是使用单一索引,而是使用联合索引 (name,sex),这样的话再执行这个查询语句就可以根据辅助索引查询到的结果。

索引下推

MySQL 5.6 之前是没有索引下推这个功能,后面为了提高性能,避免不必要的回表,就有了索引下推优化的功能。

假如我们有一个用户表,并且使用用户的 name,age 两个字段建立联合索引,name 在没有索引下推的功能,执行下面的 sql

select * from tuser where name like '张%' and age=10 and ismale=1;

没有索引下推: 根据索引查询 name like '张%' 的数据,它不会再比较 age 值是否符合要求,而是直接获取到主键值,然后再回表查询,回表后再对比 ageismale 是否符合条件。

有索引下推: 索引下推会再次根据 age 进行比较,符合条件的数据才会进行回表查询,这样就减少了不必要的回表查询,提升了性能。

参考链接