目录
mysql架构
server层包括:
连接器:身份认证和权限相关
查询缓存:执行查询语句的时候,会先查询缓存
分析器:没有命中缓存的话,SQL 语句就会经过分析器,对sql进行语法检查
优化器: 按照 MySQL 认为最优的方案去执行,产生执行计划和选取索引
执行器:操作存储引擎,返回结果
引擎层:
插件式存储引擎,支持多种引擎,5.5版本之后默认使用的是innoDB存储引擎,主要负责数据的存储和读取。下面我们就着重来介绍它。
首先我们需要了解存储引擎是基于表的而不是数据库。
innoDB存储引擎
优点
1)支持事物(undolog) ,外键
2)支持数据库崩溃或数据快速恢复(redolog)
3) 支持行锁
4) 支持MVCC机制
5) 使用B+Tree作为索引数据结构,索引文件和数据文件不分离io的调度次数更少
索引
索引的数据结构
我们知道创建索引是为了提高数据库的查询速度,减少 IO 调度次数。而innodb引擎内部使用的就是B+Tree
为什么选择B+Tree?
常见快速检索元素的数据结构:哈希表,平衡搜索二叉树,跳表,B树,B+树
哈希表
哈希表是键值对的集合,通过键(key)即可快速取出对应的值(value),因此哈希表可以快速检索数据(接近 O(1))。
弊端:不支持顺序和范围查询。并且,每次 IO 只能取一个数据。
平衡搜索二叉树
AVL,红黑树都属于平衡搜索二叉树
AVL和红黑树的查询时间复杂度都是O(logn),并且红黑树插入和删除节点时只需进行 O(1) 次数的旋转和变色操作。
弊端:每个树节点仅存储一个数据,而每次进行磁盘 IO 时只能读取一个节点的数据,如果需要查询的数据分布在多个节点上,那么就需要进行多次磁盘 IO。 磁盘 IO 是一项耗时的操作,在设计数据库索引时,我们需要优先考虑如何最大限度地减少磁盘 IO 操作的次数。
B树和B+树
B 树也称 B-树,全称为 多路平衡查找树 ,B+ 树是 B 树的一种变体。B 树和 B+树中的 B 是 Balanced
(平衡)的意思。
多路平衡查找树:每个节点可以存储多组数据,每个节点下可以有多个子节点
B树和B+树异同:
- B 树的所有节点既存放键(key) 也存放数据(data),而 B+树只有叶子节点存放 key 和 data,其他内节点只存放 key。
- B 树的叶子节点都是独立的;B+树的叶子节点有一条引用链指向与它相邻的叶子节点。
- B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显。
- 在 B 树中进行范围查询时,首先找到要查找的下限,然后对 B 树进行中序遍历,直到找到查找的上限;而 B+树的范围查询,只需要对链表进行遍历即可。
综上,B+树与 B 树相比,具备更少的 IO 次数、更稳定的查询效率和更适于范围查询这些优势
B+树的每一个叶子节点都是一个数据页,树的每一层的节点之间使用的是双向连表,每一个节点内部,也就是没以页数据内部使用单项连表来组织数据的逻辑顺序。
索引种类划分
按照底层存储方式角度划分:
聚簇索引(聚集索引):索引结构和数据一起存放的索引,InnoDB 中的主键索引就属于聚簇索引。 非聚簇索引(非聚集索引):索引结构和数据分开存放的索引,二级索引(辅助索引)就属于非聚簇索引。MySQL 的 MyISAM 引擎,不管主键还是非主键,使用的都是非聚簇索引。
按照应用维度划分:
- 主键索引:加速查询 + 列值唯一(不可以有 NULL)+ 表中只有一个。
- 普通索引:仅加速查询。
- 唯一索引:加速查询 + 列值唯一(可以有 NULL)。
- 覆盖索引:一个索引包含(或者说覆盖)所有需要查询的字段的值。
- 联合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并。
- 全文索引:对文本的内容进行分词,进行搜索。目前只有
CHAR
、VARCHAR
,TEXT
列上可以创建全文索引。一般不会使用,效率较低,通常使用搜索引擎如 ElasticSearch 代替。若想详细了解索引结构请移步 :MySQL索引详解 | JavaGuide
为什么索引查询快?
索引可以提高数据的查询速度,他又非索引查询相比到底快在哪呢?想了解往下看
知识补充:数据的存储的逻辑顺序和主键的顺序是相同,如果一个表中没有设置主键那么会将表中的唯一索引设置为隐藏主键,如果没有唯一索引那么隐藏字段就生效了,会在隐藏字段中生成一个6字节的自增主键。(B+Tree:胖而矮)
非索引查询:加表锁,走全表扫描,直接扫描主键索引的叶子节点,从第一个节点依次查找向后遍历所有叶子节点查询。
索引查询: 除了覆盖索引,其他索引先查询当前索引树从发根节点到叶子节点定位到主键值,再去主键索引从根节点向下到叶子节点定位到目标元素。
这样砸一看反而非索引查询无需回表,那么不应该查询快吗?
让我们来详细拆分:
对于有where条件的查询:
1. 基于索引字段查询:
主键/覆盖索引:从根节点到叶子节点的一次查找即可定位到目标数据.
普通索引:先走普通索引从根节点到叶子节点定位到主键值,在基于主键去主键索引中从根节点向下定位到叶子节点即可定位到目标数据.
2.非索引查询:直接从主键索引的首个叶子节点开始遍历叶子节点,并且需要取出data数据域来判断参数是否匹配。
小结:根据b+tree的数据结构性质,显然索引查询的效率更高,索引查询的时间复杂度为O(logn),非索引查询时间复杂度 O(n),并且非索引查询的数量级比索引查询的数量级大的多,此外非索引查询还需要解析data域来一次判断。
对于没有查询条件的查询:
查询数据为索引字段:显然就是覆盖索引,返回覆盖索引的所有叶子节点。
查询的数据有非索引字段:返回主键索引的所有叶子节点,且需根据查询的字段列从data中取出想要的数据。
没有查询条件区别不大。
redolog和undolog
在讲解重做日志和回滚日志先讲解以下Server层的日志模块binglog(归档日志)
binglog:是一种逻辑日志,记录了所有涉及到更新数据的逻辑操作,并且顺序写,追加写,写满一个文件,就创建一个新的文件继续写,不会覆盖以前的日志,保存的是全量的日志。保证了数据库的一致性,数据库的数据备份,主从,从从都离不开binglog日志。
redolog(重做日志):是一种物理日志,是innodb引擎特有,记录了数据页上做了什么修改, 是循环写,是一个日志文件组,日志空间大小是固定,全部写满就从头开始,并将日志刷入到磁盘。也就是说哦redolog中记录的是未刷盘的数据。让mysql有了崩溃恢复能力。保证了事物的持久性。
undolog(回滚日志) : 记录了所有事物提交前的状态,当事物提交失败后可以快速回滚,也是mvcc机制实现的核心。保证了事物的原子性。
知识补充:mysql中的数据以页为单位,当查询一条数据时会从磁盘上读取一页数据并放入到buffer pool缓存池中,后续的查找都是从缓冲池中查询若未命中再去磁盘加载,减少磁盘io开销,更新数据时若缓存中有要修改的数据就直接在缓存池中修改,然后将页的修改操作记录到redolog buffer缓存区,然后再刷盘。
redolog如何保证事物的持久性?
1)在对数据页进行修改操作后,会将修改记录到redolog buffer缓存区中然后再提交事物。
2)后台线程会每个一秒将redolog buffer内的数据刷盘,如果再事物提交后没有即使刷盘最多会丢失一秒的数据,此外可以设置再事物提交后执行刷盘操作。
综上所述:redolog 日志记录了所有数据的修改操作,并且最多只丢失一秒数据,如果设置了事物提交后刷盘发生数据丢失的概率更低,因此若数据库崩溃后可直接加载redolog进行数据恢复。
undolog如何保证事物的原子性?
undolog记录了事物修改前的数据状态,在表信息修改前会将数据copy到undolog中,记录了多个数据版本,当事物回滚时可以借助undolog恢复事物提交前的数据版本。