MySQL的聚簇索引和二级索引

索引按照物理实现方式,索引可以分为 2 种:聚簇(聚集)和非聚簇(非聚集)索引。也可以把非聚集索引称为二级索引或者辅助索引。

一.聚簇索引

聚簇索引 并不是一种单独的索引类型,而是一种数据存储方式 (所有的用户记录都存储在了叶子节点),也就是所谓的索引即数据,数据即索引

特点:

1.使用记录主键值的大小进行记录和页的排序,这包括三个方面的含义:

(1)页内的记录是按照主键的大小顺序排成一个单向链表 。

(2)各个存放用户记录的页也是根据页中用户记录的主键大小顺序排成一个双向链表 。

(3)存放目录项记录的页分为不同的层次,在同一层次中的页也是根据页中目录项记录的主键大小顺序排成一个双向链表 。

2.B+树的 叶子节点 存储的是完整的用户记录。

所谓完整的用户记录,就是指这个记录中存储了所有列的值(包括隐藏列)。

把具有这两种特性的B+树称为聚簇索引,所有完整的用户记录都存放在这个聚簇索引的叶子节点处。这种聚簇索引并不需要我们在MySQL语句中显式的使用INDEX语句去创建,InnoDB存储引擎会自动地创建聚簇索引。

优点:

数据访问更快 ,因为聚簇索引将索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快

聚簇索引对于主键的 排序查找 和 范围查找 速度非常快

按照聚簇索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不用从多个数据块中提取数据,所以 节省了大量的IO操作 。

缺点:

插入速度严重依赖于插入顺序 ,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,一般都会定义一个自增的ID列为主键

更新主键的代价很高 ,因为将会导致被更新的行移动。因此,对于InnoDB表,一般定义主键为不可更新

二级索引访问需要两次索引查找 ,第一次找到主键值,第二次根据主键值找到行数据

限制:

对于MysQL数据库目前只有InnoDB数据引擎支持聚簇索引,而MylSAM并不支持聚簇索引。

由于数据物理存储排序方式只能有一种,所以每个MySQL的表只能有一个聚簇索引。一般情况下就是该表的主键。

如果没有定义主键,InnoDB会选择非空的唯一索引代替。如果没有这样的索引,InnoDB会隐式的定义一个主键来作为聚簇索引。

为了充分利用聚簇索引的银簇的特性,所以InnoDB表的主键列尽量选用有序的顺序id,而不建议用无序的id,比如UUID、MD5、HASH、字符串列作为主键无法保证数据的顺序增长

二.二级索引(非聚簇索引、辅助索引)

用c2列的大小作为数据页、页中记录的排序规则,再建一棵B+树,效果如下图所示:

这个B+树与上边介绍的聚簇索引有几处不同:

使用记录c2列的大小进行记录和页的排序,这包括三个方面的含义:

(1)页内的记录是按照c2列的大小顺序排成一个单向链表

(2)各个存放用户记录的页也是根据页中记录的c2列大小顺序排成一个双向链表

(3)存放目录项记录的页分为不同的层次,在同一层次中的页也是根据页中目录项记录的c2列大小顺序排成一个双向链表

(4)B+树的叶子节点存储的并不是完整的用户记录,而只是c2列+主键这两个列的值

(5)目录项记录中不再是主键+页号的搭配,而变成了c2列+页号的搭配

以查找c2列的值为4的记录为例,查找过程如下:

1.确定 目录项记录页

根据根页面 ,也就是页44,可以快速定位到目录项记录所在的页为页42(因为2<4< 9 )

2.通过目录项记录页确定用户记录真实所在的页

在页42中可以快速定位到实际存储用户记录的页,但是由于c2列并没有唯一性约束,所以c2列值为4的记录可能分布在多个数据页中,又因为2<4<=4,所以确定实际存储用户记录的页在页34和页35中

3.在真实存储用户记录的页中定位到具体的记录:

到页34和页35中定位到具体的记录

4.但是这个B+树的叶子节点中的记录只存储了c2和c1〔也就是主键)两个列,所以必须再根据主键值去聚簇索引中再查找一遍完整的用户记录。

概念:回表

根据这个以c2列大小排序的B+树只能确定要查找记录的主键值,所以如果想根据c2列的值查找到完整的用户记录的话,仍然需要到聚簇索引中再查一遍,这个过程称为回表。也就是根据c2列的值查询一条完整的用户记录需要使用到 2 棵B+树!

相关推荐
XiaoLeisj30 分钟前
【MyBatis】深入解析 MyBatis XML 开发:增删改查操作和方法命名规范、@Param 重命名参数、XML 返回自增主键方法
xml·java·数据库·spring boot·sql·intellij-idea·mybatis
dleei1 小时前
MySql安装及SQL语句
数据库·后端·mysql
信徒_2 小时前
Mysql 在什么样的情况下会产生死锁?
android·数据库·mysql
嘴对嘴编程3 小时前
oracle数据泵操作
数据库·oracle
苹果酱05673 小时前
Golang标准库——runtime
java·vue.js·spring boot·mysql·课程设计
·薯条大王9 小时前
MySQL联合查询
数据库·mysql
morris13111 小时前
【redis】redis实现分布式锁
数据库·redis·缓存·分布式锁
hycccccch11 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
这个懒人12 小时前
深入解析Translog机制:Elasticsearch的数据守护者
数据库·elasticsearch·nosql·translog
Yan-英杰12 小时前
【百日精通JAVA | SQL篇 | 第二篇】数据库操作
服务器·数据库·sql