[转帖]深入理解mysql-第六章 mysql存储引擎InnoDB的索引-B+树索引
一、引入索引
在没有索引的情况下,不论是根据主键列或者其他列的值进行查找,由于我们并不能快速的定位到记录所在的页,所以只能从第一个页沿着双向链表一直往下找,因为要遍历所有的数据页,时间复杂度就是O(n),所以这种方式显然是超级耗时的。所以我们需要采取一定的数据结构来存储数据,方便我们进行数据的增删改查操作。
问题的需求大致定义清楚了,我们现在回想一下,能否利用已经学习过的数据结构解决这个问题呢?支持快速查询、插入等操作的动态数据结构,我们已经学习过散列表、平衡二叉查找树、跳表。
我们先来看散列表。散列表的查询性能很好,时间复杂度是 O(1)。但是,散列表不能支持按照区间快速查找数据。所以,散列表不能满足我们的需求。
我们再来看平衡二叉查找树。尽管平衡二叉查找树查询的性能也很高,时间复杂度是 O(logn)。而且,对树进行中序遍历,我们还可以得到一个从小到大有序的数据序列,但这仍然不足以支持按照区间快速查找数据。
我们再来看跳表。跳表是在链表之上加上多层索引构成的。它支持快速地插入、查找、删除数据,对应的时间复杂度是 O(logn)。并且,跳表也支持按照区间快速地查找数据。我们只需要定位到区间起点值对应在链表中的结点,然后从这个结点开始,顺序遍历链表,直到区间终点对应的结点为止,这期间遍历得到的数据就是满足区间值的数据。
这样看来,跳表是可以解决这个问题。实际上,数据库索引所用到的数据结构跟跳表非常相似,叫作 B+ 树。不过,它是通过二叉查找树演化过来的是m叉查找树,而非跳表。B+ 树发明于 1972 年,跳表发明于 1989 年,有可能跳表发明者参考了B+树的设计。
二、B+树索引的设计
上一章我们讲到,InnoDB
数据页的7个组成部分,知道了各个数据页可以组成一个双向链表
,而每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表
,每个数据页都会为存储在它里边儿的记录生成一个页目录
,在通过主键查找某条记录的时候可以在页目录
中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录。
以上是数据在页中的查找过程,当数据页中插入数据呢?因为数据是从小到大排序的(主键值),同时每个数据页是固定大小的(16K),所以当数据插入一个满的数据页时,会发生页的分裂,将大的数据迁移到新数据页(页码数随机),这也叫页分裂。当然删除数据也会造成数据页的删除。
以上是数据在页中的操作,那在查找数据时如何快速定位到具体的数据页呢?这时候目录页(实际也是数据页,为了和实际存储数据的数据页区分开)就出现了,目录页和数据页的结构一样,目录页的key存储各个页的最小记录的主键值,page存储对应的页号。这样我们就可以快速定位要找到的页,然后进行上面讲的数据页中的查找。
目录页中的目录项
其实长得跟我们的用户记录一样,只不过目录项
中的两个列是主键
和页号
而已,所以复用了之前存储用户记录的数据页来存储目录项,为了和用户记录做一下区分,表示目录项的记录称为目录项记录,他们的
记录头信息里的record_type
属性和普通数据不一样:
0
:普通的用户记录1
:目录项记录2
:最小记录3
:最大记录
目录项记录
和普通的用户记录
的不同点:
目录项记录
的record_type
值是1,而普通用户记录的record_type
值是0。目录项记录
只有主键值和页的编号两个列,而普通的用户记录的列是用户自己定义的,可能包含很多列,另外还有InnoDB
自己添加的隐藏列。还记得我们之前在唠叨记录头信息的时候说过一个叫
min_rec_mask
的属性么,只有在存储目录项记录
的页中的主键值最小的目录项记录
的min_rec_mask
值为1
,其他别的记录的min_rec_mask
值都是0
。
除了上述几点外,这两者就没啥差别了,它们用的是一样的数据页(File Header
中页面类型都是0x45BF
),页的组成结构也是一样的(就是我们前边介绍过的7个部分),都会为主键值生成Page Directory
(页目录),从而在按照主键值进行查找时可以使用二分法来加快查询速度。
当然如果我们表中的数据非常多则会产生很多存储目录项记录
的页,那我们怎么根据主键值快速定位一个存储目录项记录
的页呢?其实就是目录页上一层在生成自己的目录页。如下图:
从图中可以看出来,一个B+
树的节点其实可以分成好多层。因为每一个数据页能放很多条数据,所以树的高度不会很高,假设所有存放用户记录的叶子节点代表的数据页可以存放100条用户记录,所有存放目录项记录的内节点代表的数据页可以存放1000条目录项记录,那么:
如果
B+
树只有1层,也就是只有1个用于存放用户记录的节点,最多能存放100
条记录。如果
B+
树有2层,最多能存放1000×100=100000
条记录。如果
B+
树有3层,最多能存放1000×1000×100=100000000
条记录。如果
B+
树有4层,最多能存放1000×1000×1000×100=100000000000
条记录。
扩展一下,B-树、B 树跟 B+ 树的不同点主要集中在这几个地方:
- B- 树就是 B 树,英文翻译都是 B-Tree,这里的“-”并不是相对 B+ 树中的“+”,而只是一个连接符。
- B+ 树中的节点不存储数据,只是索引,而 B 树中的节点存储数据;
- B 树中的叶子节点并不需要链表来串联。
三、索引的分类
3.1 聚簇索引
上面我们介绍索引时候,实际已经了解到,mysql的存储引擎InnoDB在存储数据记录的时候,已经使用记录主键值的大小进行记录和页的排序,按照B+
树的数据结构存储目录,叶节点存储页码,也可以理解为叶子结点存储了数据,非叶子节点都是存储的目录信息,也就是索引信息,或者说这本身就是一个索引,也就是聚簇索引。他的主要存储结构:
页内的记录是按照主键的大小顺序排成一个单向链表。
各个存放用户记录的页也是根据页中用户记录的主键大小顺序排成一个双向链表。
存放目录项记录的页分为不同的层次,在同一层次中的页也是根据页中目录项记录的主键大小顺序排成一个双向链表。
B+
树的叶子节点存储的是完整的用户记录(实际也可以理解为叶子节点是页码,B+不存储数据)。
聚簇索引
并不需要我们在MySQL
语句中显式的使用INDEX
语句去创建(后边会介绍索引相关的语句),InnoDB
存储引擎会自动的为我们创建聚簇索引。
3.2 二级索引
聚簇索引
只能在搜索条件是主键值时才能发挥作用,因为B+
树中的数据都是按照主键进行排序的。我们针对某一列的查询条件快速定位,可以对特定的列进行B+树的创建,构建索引,提高查询效率。这样我们构建这一列的B+树的特点就是:
- 页内的记录是按照
c2
列的大小顺序排成一个单向链表。 - 各个存放用户记录的页也是根据页中记录的
c2
列大小顺序排成一个双向链表。 - 存放目录项记录的页分为不同的层次,在同一层次中的页也是根据页中目录项记录的
c2
列大小顺序排成一个双向链表。 B+
树的叶子节点存储的并不是完整的用户记录,而只是c2列+主键
这两个列的值。- 目录项记录中不再是
主键+页号
的搭配,而变成了c2列+页号
的搭配。
当我们进行查询的时候,查询步骤和聚簇索引一样,限定从目录页定位到数据页页码,然后根据数据页内查找找到对应的行,拿到行中数据的主键进行聚簇索引的查找和定位具体数据,这就是回表操作,因为建立非主键的索引会重新建一个b+树,查询数据因为要有回表操作二查询两次B+树,所以也是二级索引命名的由来。
3.3 联合索引
同二级索引,我们也可以对多个列进行加索引操作,实际就是以两个列的大小排序建立一个B+树,比方说我们想让B+
树按照c2
和c3
列的大小进行排序:
- 先把各个记录和页按照
c2
列进行排序。 - 在记录的
c2
列相同的情况下,采用c3
列进行排序。 每条
目录项记录
都由c2
、c3
、页号
这三个部分组成,各条记录先按照c2
列的值进行排序,如果记录的c2
列相同,则按照c3
列的值进行排序。B+
树叶子节点处的用户记录由c2
、c3
和主键c1
列组成。
四、索引创建SQL命令
我们可以在创建表的时候创建非主键字段的二级索引和联合索引:
-
CREATE TALBE 表名 (
-
各种列的信息 ··· ,
-
[KEY|INDEX] 索引名 (需要被索引的单个列或多个列)
-
)
其中的KEY
和INDEX
是同义词,任意选用一个就可以。我们也可以在修改表结构的时候添加索引:
ALTER TABLE 表名 ADD [INDEX|KEY] 索引名 (需要被索引的单个列或多个列);
也可以在修改表结构的时候删除索引:
ALTER TABLE 表名 DROP [INDEX|KEY] 索引名;
比方说我们想在创建index_demo
表的时候就为c2
和c3
列添加一个联合索引
,可以这么写建表语句:
-
CREATE TABLE index_demo(
-
c1 INT,
-
c2 INT,
-
c3 CHAR(1),
-
PRIMARY KEY(c1),
-
INDEX idx_c2_c3 (c2, c3)
-
);
[转帖]深入理解mysql-第六章 mysql存储引擎InnoDB的索引-B+树索引的更多相关文章
- mysql 开发基础系列10 存储引擎 InnoDB 介绍
一. 概述: InnoDB存储引擎提供了具有提交,回滚,和崩溃恢复能力的事务安全,对比MYISAM 的存储引擎,InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引.它的特点有如下: ...
- [MySQL Reference Manual]15. 其他存储引擎
15. 其他存储引擎 15. 其他存储引擎 15.1 设置存储引擎 15.2 MyISAM存储引擎 15.2.1 MyISAM启动选项 15.2.2 Key的空间要求 15.2.3 MyISAM表存储 ...
- 第六章 mysql日志
第六章 mysql日志 一 错误日志 错误日志的默认存放路径是 mysql 存放数据的地方 hostname.err 1. 修改错误日志存放路径 [mysqld] log-error=/data/m ...
- MySQL性能调优与架构设计——第11章 常用存储引擎优化
第11章 常用存储引擎优化 前言: MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.每一种存储引擎都有各自的特长,也都存在一定的短处. ...
- mysql第六篇 : MySQL索引原理与慢查询优化
浏览目录 一.索引介绍 二.索引方法 三.索引类型 四.聚合索引和辅助索引 五.测试索引 六.正确使用索引 七.组合索引 八.注意事项 九.查询计划 十.慢日志查询 十一.大数据量分页优化 一.索引介 ...
- [转帖]mysql常用存储引擎(InnoDB、MyISAM、MEMORY、MERGE、ARCHIVE)介绍与如何选择
mysql常用存储引擎(InnoDB.MyISAM.MEMORY.MERGE.ARCHIVE)介绍与如何选择原创web洋仔 发布于2018-06-28 15:58:34 阅读数 1063 收藏展开 h ...
- [转帖]一文看懂mysql数据库本质及存储引擎innodb+myisam
一文看懂mysql数据库本质及存储引擎innodb+myisam https://www.toutiao.com/i6740201316745740807/ 原创 波波说运维 2019-09-29 0 ...
- MySql(十一):MySQL性能调优——常用存储引擎优化
一.前言 MySQL 提供的非常丰富的存储引擎种类供大家选择,有多种选择固然是好事,但是需要我们理解掌握的知识也会增加很多.本章将介绍最为常用的两种存储引擎进行针对性的优化建议. 二.MyISAM存储 ...
- 常用Mysql存储引擎--InnoDB和MyISAM简单总结
常用Mysql存储引擎--InnoDB和MyISAM简单总结 2013-04-19 10:21:52| 分类: CCST|举报|字号 订阅 MySQL服务器采用了模块化风格,各部分之间保持相 ...
- mysql-介绍、MySQL部署、数据类型、存储引擎
数据库介绍 什么是数据? 数据(data)是事实或观察的结果,是对客观事物的逻辑归纳,是用于表示客观事物的未经加工的原始素材.数据是信息的表现形式和载体,可以是符号.文字.数字.语音.图像.视频等. ...
随机推荐
- ZincSearch轻量级全文搜索引擎入门到
ZincSearch轻量级全文搜索引擎入门到 Zinc是一个用于对文档进行全文搜索的搜索引擎.它是开源的,内置在 Go 中.Zinc不是从头开始构建索引引擎,而是构建在 bluge 之上,这是一个出色 ...
- 文心一言 VS 讯飞星火 VS chatgpt (42)-- 算法导论5.4 6题
六.假设将n个球投人 n 个箱子里,其中每次投球独立,并且每个球等可能落入任何箱子.空箱子的数目期望是多少?正好有一个球的箱子的数目期望是多少? 文心一言: 这是一个典型的概率问题.首先,我们可以通过 ...
- shared_preferences缓存
封装 import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; class JSpUtil ...
- java中使用对象储存OSS
首先获取 ACCESS_KEYSECRET 与 ACCESS_KEYID 获取 ENDPOINT 与 ALI_DOMAIN 与 BUCKET_NAME(存储空间名称) 依赖 <!-- 图片 ...
- 窗口到底有多滑动?揭秘TCP/IP滑动窗口的工作原理
本文分享自华为云社区<窗口到底有多滑动?揭秘TCP/IP滑动窗口的工作原理>,作者: Lion Long. 当涉及网络性能优化和数据传输可靠性时,TCP/IP滑动窗口是一个关键的技术.本文 ...
- 5大特性,带你认识化繁为简的华为云CodeArts Deploy
摘要:2月27日,华为云发布持续部署服务CodeArts Deploy,通过模块化自由编排部署流程,实现软件的自动化部署,帮助企业软件产品的快速.高效.高质量交付. 本文分享自华为云社区<化繁为 ...
- 升级win11显示:此版本的windows不支持该处理器—如何强升win11?
今天的我微信笔记本 msi gp62 mvr 无论是win10升级到win11 还是安装win11都无法安装.显示: Windows 11不支持该处理器 win11系统升级标准要求相比win10来说有 ...
- 对话 BitSail Contributor | 吴畅:从好奇,到深入
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 2022 年 10 月,字节跳动 BitSail 数据引擎正式开源.同期,社区推出 Contributor 激励计 ...
- cxf 动态调用 WebService No compiler detected, make sure you are running on top of a JDK instead of a JRE
WebService cxf No compiler detected, make sure you are running on top of a JDK instead of a JRE [202 ...
- 多种方式实现 Future 回调返回结果
JDK 实现 public class FutureTest { public static void main(String[] args) throws Exception { Executor ...