MySQL-index

索引介绍

生活中随处可见索引的例子,例如词典、火车站车次表、图书目录等。他们的原理和目标都是一样的,就是通过不断缩小想要获取数据的范围,将随机的时间变成顺序的事件,也就是我们总是通过同一种查询方式来锁定数据。
对于MySQL,索引是一个单独的、存储在磁盘上的数据库结构,它们包含着对数据表里所有记录的引用指针。使用索引用于快速找出在某个或多个列中有一特定值的行,所有MySQL列类型都可以被索引,对相关列使用索引是提高查询操作速度的最佳途径。

索引结构

HASH索引

Hash索引是一种常见的索引,它的单条记录查询的效率非常高,时间复杂度为O(1)。但是Hash索引却不是常用的数据库索引类型,MySQL innodb存储引擎就不支持Hash索引。主要有以下原因:

有序数组

有序数组用于等值查询和范围查询表现都很优秀,但是作为数组存在一个致命缺陷,就是如果数据有更改的话,会导致他的更改节点后续的节点都需要改变。因此有序数组更适合于存储静态数据。
对于历史数据例如淘宝历史订单/支付宝历史账单等数据就很适合使用有序数组。

二叉树

先来介绍下二叉树的特点:

极端情况下会出现二叉树链化的情况,其次二叉树在数据量越来越多时层高也会随之增加,层高越高就代表IO次数越多,检索效率越慢

B树

从B树的结构图中可以看到每个节点中不仅包含数据的 key 值,还有 data 值。

而每页的存储空间是有限的,如果 data 比较大,会导致每个节点的 key 存储的较少,当数据量较大的时候,同样会导致B树很深,从而增加了磁盘 IO 的次数,进而影响查询效率。

B+树

MySQL 中最常用的索引的数据结构是 B+ 树,他有以下特点:

  1. 在 B+ 树中,所有数据记录节点都是按照键值的大小存放在同一层的叶子节点上,而非叶子结点只存储key的信息,这样可以大大减少每个节点的存储的key的数量,降低B+ 树的高度
  2. B+ 树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。
  3. B+ 树的层级更少:相较于 B 树 B+ 每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快
  4. B+ 树查询速度更稳定:B+ 所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
  5. B+ 树天然具备排序功能:B+ 树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
  6. B+ 树全节点遍历更快:B+ 树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像 B 树一样需要对每一层进行遍历,这有利于数据库做全表扫描。

InnoDB中,最小存储单元是页,1页的大小约16k,一个节点的大小就是16k,也就是说B+树每个节点可以存储16k的数据。
假设主键类型为bigint,大小为8Byte,指针可以占有6Byte,总共14Byte,则可以计算出一个非叶子节点可以存放大概16KB/14B=1170个“主键+指针组合”;
主键类型为int,大小为4Byte,指针6Byte,共10Byte,可计算出大概存放16KB/10K=1600数据;
叶子节点需要存放数据,假设一条数据的大小是1k,则叶子节点可存储16条数据。
因此bigint类型:
两层B+树:1170 * 16= 18720
三层B+树:1170 * 1170 * 16 = 21902400
int类型则翻倍

索引创建原则

索引是建立在数据库表的某些列上的 。因此,在建立索引的时候,就需要考虑某些列应该寄哪里索引,某些列不应该建立索引。

应该建立索引的列

不应该建立索引的列

索引类别

ALTER TABLE tableName ADD PRIMARY KEY(column);
CREATE UNIQUE INDEX indexName ON tableName('column'(length))
# or
ALTER TABLE tableName ADD UNIQUE (column);
CREATE INDEX IndexName ON `TableName`(`字段名`(length));
# 或者
ALTER TABLE TableName ADD INDEX IndexName(`字段名`(length));

索引下推

什么是索引下推

索引下推(Index Condition Pushdown,简称ICP),是MySQL5.6后的新特性,可以减少回表查询次数,提高查询效率。

索引下推原理

MySQL服务层负责SQL语法解析,生成执行计划等,并调用引擎层去执行数据的存储和检索。
索引下推 的下推 是将部分上层(服务层)负责的事情,交给下层(引擎层)去处理。

未使用ICP,MySQL的查询:

  1. 存储引擎读取索引记录;
  2. 根据索引中的主键值,定位并读取完整的行记录;
  3. 存储引擎把记录交给Server层去检测该记录是否满足Where检索条件
    使用ICP,MySQL的查询:
  4. 存储引擎读取索引记录(不是完整的行记录);
  5. 判断Where条件部分能否用索引中的列来做检查,条件不满足,则处理下一行索引记录;
  6. 条件满足,使用索引中的主键去定位并读取完整的行记录(回表);
  7. 存储引擎把记录交给Server层,Server层判断该记录是否满足Where条件的其余部分。

索引下推使用条件

索引下推的目的是为了减少回表次数,也就是要减少IO操作。对于InnoDB聚簇索引来说,数据和索引是在一起的,不存在回表这一说。

索引失效