一文搞定InnoDB索引

4 篇文章 0 订阅
2 篇文章 0 订阅

关于InnoDB索引及相关知识的个人理解,如遇错误欢迎指正。

InnoDB的索引

InnoDB的索引分为两类:

聚集索引(clustered index)
  • 聚集索引的叶子节点存储行记录
  • 一个InnoDB引擎的表,必须有且只有一个聚集索引
  • 聚集索引的三种情况:
    • 如果表定义了PK(primary key),则PK就是聚集索引;
    • 如果表没有定义PK,则第一个not NULL unique列是聚集索引;
    • 否则,InnoDB会创建一个隐藏的row-id作为聚集索引;
普通索引(secondary index)
  • 一个InnoDB引擎的表,可以有任意个普通索引
  • 普通索引的叶子节点存储主键值(MyISAM的索引叶子节点存储记录指针,不要混淆)
  • 普通索引也包含常见的索引种类:
    • 唯一索引(Unique Indexes)
    • 列索引(Column indexes,就是普通的INDEX)
    • 联合/复合索引(Composite indexes,就是多字段的INDEX)
    • 全文索引(FULLTEXT Indexes,MySQL5.6开始,InnoDB也有全文索引了)
    • 空间索引(Spatial Indexes)

假设有表:

table name (
	id PRIMARY KEY, 
	name KEY, 
	sex, 
	flag
);

其中:id是聚集索引,name是普通索引。

回表是什么

回表这个名词其实没有直接的英文翻译,我仅在《高性能MySQL》英文原版中找到几句相关的描述(大概都在第五章后半段):

look up full rows from the table to retrieve columns”
" it will have to look up each row it finds in the index"

所以其实很简单,回表,就是表达当WHERE索引列的时候,无法直接获取到查询的列,从而导致我们需要再次回到表中去查询相应的内容,就是我们平常所说的“回表”
见下图
在这里插入图片描述
两个B+树索引分别如上图:

  • id为PK(primary key),聚集索引,叶子节点存储行记录;
  • name为KEY,普通索引,叶子节点存储主键值(id);

由此可见,普通索引的查询过程,需要扫码两遍索引树,这个行为也称之为回表
这里面做一个细化的区分:

  • 当WHERE列是索引列的时候,SELECT该列就不需要回表
  • 当WHERE列是索引列的时候,SELECT其他列就需要回表(主键查询除外,因为主键查询即可返回该行全部列,不需要回表)
  • 当WHERE列没有索引的话,那就不用多提了,全表扫描

覆盖索引/索引覆盖(covering index)

以下截图来自于MySQL术语表
在这里插入图片描述

覆盖索引
覆盖索引是一次查询(query)便取回全部列的索引。它替代了使用索引值作为指针来查找全部表行,这种查询返回的值来自于索引结构,节省硬盘I/O。相比MyISAM,InnoDB可以将这项优化技术应用在更多的列上,因为InnoDB的普通索引还包括主键列。不过InnoDB不能应用这项技术于由事务修改的表的查询,直到事务结束
在正确的查询条件下,任何列索引(column index)或复合索引(composite index)都可以作为覆盖索引。尽可能设计索引和查询以利用这种优化技术。

回到普通索引(Secondary indexes)

上面引文有一句话让人耳目一新,就是“InnoDB secondary indexes also include the primary key columns”,InnoDB普通索引包含主键列?之前不是说主键列一般都是聚集索引吗?

这是一个语义误区,实际上MySQL官方文档对于Secondary indexes的定义是,除聚集索引以外的所有索引都称为辅助索引(或叫普通索引),见下图
在这里插入图片描述
总结:也就是说,聚集索引通常为主键,但是普通索引除了包含自己的列以外,还会包含主键列的值,聚集索引在InnoDB引擎的表结构中必须要有,但是普通索引可能有任意个(0个,1个,甚至更多)

索引类型(Index types)

此索引类型非彼索引类型,所以有时候加上英文来区分定义是个很好的选择
以下是MySQL官网对于每种存储引擎所支持的索引类型:
(注意:这里看到MyISAM不支持HASH类型)
在这里插入图片描述
这里不翻译了,总结几个要点:

  • 表中按顺序,第一个类型即为该引擎的默认类型,除非创建时指定其他的
  • 表中以外的其他类型不支持使用CREATE……USING方式创建
  • 全文索引不支持上述表中类型,它由存储引擎来决定
  • 空间索引不支持上述表中类型,它由R-tree索引实现

面试经常遇到的提问

为什么InnoDB使用B+tree结构而不是HASH结构?

  • 首先是InnoDB不支持设置为HASH结构
  • 由于HASH结构数据存储没有顺序性,不好做范围查询排序,比较适合定值查询
  • B+tree很好的解决了上述问题
  • B+tree是多路平衡查询树,节点是天然有序的,所以不需要做全表扫描
  • (怎么个有序法?)左子节点小于父节点、父节点小于右子节点
  • HASH结构索引不支持联合索引
  • 说白了,除了定值查询快以外一无是处,而且当遇到不连续多处重复值的查询,更糟糕了

创建索引时需要考虑哪些点?

  • 为经常查询、排序、分组的列创建索引
  • 为数据量小的类型创建索引(比如各种数字类型而非字符串类型)
  • 尽量选择区分度高的列,而非重复值比较多的列上创建索引(如gender、status、type)
  • 在业务场景满足的条件下,唯一索引是个不错的选择
  • 尽量不要在改动特别频繁的列创建索引(还是status、update_time之类的)
  • 相比“%xxxx%”,“xxxx%” 是可以用到索引的
  • 联合索引的创建要遵循最左前缀匹配原则

什么是最左匹配原则?
根据业务需求,where子句中使用最频繁的一列放在最左边,因为MySQL索引查询会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配。所以当我们创建一个联合索引的时候,如(key1,key2,key3),相当于创建了(key1)、(key1,key2)和(key1,key2,key3)三个索引,这就是最左匹配原则。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值