你真的懂数据库的索引吗?MySql索引详谈
索引在数据库中是一个绝对重点的概念,也是面试中必问的知识点,必须深入学习一下
我们选取Mysql的索引来好好研究下
先来看看官方是如何定义索引的:
- 索引(Index)是帮助 MySQL 高效获取数据的数据结构
所以,我们可以说,索引是一种数据结构,那么是什么数据结构呢?Mysql给出的答案是B+树
B+树是B树的延申,树我们知道,在构建树的时候,是会进行一个排序并进行平衡处理的,所以,我们得到索引就是排好序的数据结构,对于有序的数据结构,必定是二分查找,这种数据结构与算法大幅加快了数据库的查找速度
此处请记好索引都是排过序的
下图就是一种可能的索引(二叉树)
假设我们某张表的每行记录只有两个字段(col1-id col2-age)
-
左边是数据表,一共有两列七条记录,最左边的是数据记录的物理地址。为了加快 Col2 的查找,可以维护一个右边所示的二叉查找树,该二叉树节点存储col2的值,每个节点分别包含索引键值和一个指向对应数据记录(某一行的所有字段数据)物理地址的指针(这也称为非聚簇索引,如果直接存储的是记录,称聚簇索引)
-
这样就可以运用 二叉查找在一定的复杂度内获取到相应数据,从而快速的检索出符合条件的记录(一行称为一条记录)
-
一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上
-
该索引使用数据作为索引键,而非主键
使用索引优缺点
优点:
- 提高检索效率,降低IO成本
- 索引列对数据排序,降低数据排序成本,降低CPU消耗
缺点:
- 降低更新表速度,因为更新表时同时要更新索引
- 索引保存了主键与索引字段,并有指向实体表的指针,也会占用空间
B Tree
我们着重研究Mysql的B+树索引,轻视哈希索引
研究B+树之前,我们先看看B树是如何存储索引的
- 浅蓝色为磁盘块,包含深蓝的数据项与黄色的指针
- 两个数据项配备三个指针,P1表示小于第一个数据项的,P2表示在第一个数据项和第二个数据项之间的,P3表示大于第二个数据项的
- 真实的数据在最底下那一排磁盘块(每个深蓝代表一条行记录或指向记录的指针)
查找过程
以查找29为例
- 磁盘块1读入内存,此时一次IO
- 二分查找锁定磁盘块1的P2指针
- 把P2指向的磁盘块3读入内存,此时二次IO
- 二分查找锁定磁盘块3的P2指针
- 把磁盘块3的P2指向的磁盘块3读入内存,此时三次IO
- 找到29的行记录,结束查找,共3次IO
B+ Tree
来看看B+树是如何存储主键索引的
可以明显看见,每个磁盘块不止两个数据项和三个指针了,而是进行了扩展,那么我们可以得到
-
该B+ Tree存储主键的索引,表中有主键时自动创建该索引
-
B+树每个节点可以包含更多的节点,树的高度大幅降低
-
数据范围变为多个区间,区间越多,检索速度越快
-
非叶子节点存储主键,叶子节点存储主键和值(记录或记录的物理地址)
-
叶子节点两两指针互连,也就提高了顺序查询的性能更高(在最下面一层顺序查找)
-
实际情况中,3~4层足以支撑千万到亿级别的记录了
来看看InnoDB引擎版本的B+树
- InnoDB通过B+Tree结构对主键创建索引,称为主索引,叶子节点存储记录,
- InnoDB必然通过Key(可以是主键、唯一键、自动生成的rowid)对数据进行存储
- 如果无主键,就用唯一键,如果无唯一键,就自动生成6位rowid做唯一标识
- 在InnoDB引擎下,如果创建索引的键是其他字段而不是主键,那么在该字段的叶子节点中不存储直接的记录,存储的是该记录的主键,然后再通过主键索引找到对应的记录,称为回表
聚簇索引
聚簇索引是innodb数据引擎支持的索引,而Myisam并不支持聚簇索引
聚簇索引并不是一种单独的索引类型,而是一种数据存储方式
如下图,左侧的索引就是聚簇索引,key在磁盘的排列和索引排序保持一致,且记录直接与键值保存在一起
聚簇的好处:
- 查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不不用从多个数据块中提取数据,所以节省了大量的io操作
聚簇的限制
-
由于数据物理存储排序方式只能有一种,所以每个Mysql的表只能有一个聚簇索引。一般情况下就是该表的主键
-
为了充分利用聚簇索引的聚簇的特性,所以innodb表的主键列尽量选用有序的顺序id,而不建议用无序的id,比如uuid这种
非聚簇索引
叶子节点存储的是指向记录的指针,而非直接是记录
索引分类
单值索引
一个索引只包含单个列,一个表可以有多个单列索引
CREATE INDEX idx_customer_name ON customer(customer_name);
唯一索引
索引列的值必须唯一,但允许有空值
CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no);
主键索引
设定为主键后数据库会默认自动建立索引,以上的B+树就是说明InnoDB自动创建的索引,innodb为聚簇索引
复合索引/组合索引
即一个索引包含多个列
CREATE INDEX idx_no_name ON customer(customer_no,customer_name);
索引创建时机
- 主键自动建立唯一索引
- 频繁作为查询条件的字段
- 查询中与其他表关联的字段应该建立索引
- 组合索引性价比更高
- 排序的字段:若已排序的字段通过索引去访问,速度大增
- 查询中统计或分组的字段
以下情况不适合做索引
- 表记录太少
- InnoDB的回表机制会对非主索引的查找走两次B+树,反而更慢
select * from table where name = `zz` ;
select id from table where name = `zz` ; `
第一条语句需要走回表
第二条语句走不需要走回表,因为非主索引InnoDB叶子节点存放的就是id
不需要走回表这个过程叫索引覆盖
- 经常增删改查的字段
- where条件里用不到的字段
- 过滤性差的字段