RDBMS | 青训营笔记

37 阅读6分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 12 天

关键技术

SQL语言

image.png

SQL 执行流程

在SQL执行过程中,需要经历SQL引擎、存储引擎、以及事务引擎等模块。而其中SQL引擎又分为Parser、Optimizer、Executor几个部分:

image.png

  • 查询解析:SQL语言接近自然语言,入门容易。但是各种关键字、提作符组合起来,可以表达丰富的语意,因此想要处理SQL命令,首先将文本解析成结构化数据,也就是抽象语法树(AST)
  • 查询优化:SQL是一门表意的语言,只是说「要做什么】,而不说「怎么做」。所以需要一些复杂的逻辑选择「如何拿数据」,也就是选择一个好的查询计划。优化器的作用根据AST优化产生最优执行计划(Plan Tree)。
  • 查询执行:根据查询计划,完成数据读取、处理、写入等操作。
  • 事务引擎:处理事务一致性、并发、读写隔离等
  • 存储引擎:内存中的数据缓存区、数据文件、日志文件

SQL 引擎

SQL引擎包括了:

  • Paser:经过词法分析、语法分析生成语法树,然后对语法树进行合法性校验。
  • Optimizer:根据Parser产生的语法树,根据规则或者代价产生执行计划树。
  • Executor:根据计划树进行执行,常见的执行方式是火山模型。

Parse

image.png

  • 词法分析:将条SQL语句对应的字符串分割为一个个token,这些token可以简单分类
  • 语法分析:把词法分析的结果转为语法树。根据tocken序列匹配不同的语法规则,比如这里匹配的是update语法规则,类似的还有insert、delete、select、create、drop等等语法规则。根据语法规则匹配SQL语句中的关键字,最终输出一个结构化的数据结构。
  • 语义分析:对语法树中的信息进行合法性校验

Optimizer

选择最优查询方式

image.png

基于规则优化(RBO)

image.png

基于代价的优化(CBO)

image.png

Executor

火山模型

image.png

image.png

向量化

image.png

编译执行

image.png

代码生成之后数据库运行时仍然是一个for循环,只不过这个循环内部的代码从简单的一个虚函数调用plan.next()展开成了一系列具体的运算逻辑,这样数据就不用在各个operator之间进行传递,而且有些数据还可以直接被存放在寄存器中,进一步提升系统性能。整个操作有点像inline函数,把所有的操作inline到一个函数中去。 LLVM动态编泽执行技术,根据优化器产生的计划,动态的生成执行代码。

存储引擎

存储引擎负责了数据的底层存储、管理和访问工作。各大RDBMS存储引擎的设计都有不少的差异,这里选择MySQL的InnoDB存储引擎来介绍:

  • Buffer Pool:存储引擎位于内存中的重要结构,用于缓存数据,减少磁盘IO的开销。
  • Page:数据存储的最基本单位,一般为16KB。
  • B+u Tree:InnoDB中最常用的索引结构。

image.png

dev.mysql.com/doc/refman/…

Buffer pool

image.png

  • MySQL中每个chunk的大小一般为128M,每个blocki对应一个page,一个chunk下面有8192个block。这样可以避免内存碎片化。
  • 分成多个instance,可以有效造免并发冲突。
  • Page id%instance num得到它属于哪个instance

image.png

根据pageId决定用那个hash桶

当buffer pool里的页面都被使用之后,再需要缓存其他页面就需要淘汰已有的页面 基于什么规则淘汰:淘汰那个最近一段时间最少被访问过的缓存页了,这种思想就是典型的LRU算法。 普通的LRU算法存在缺陷,考虑到我们需要扫描10OGB的表,而我们的buffer pool只有1GB,这样就会因为全表扫描的数据量大,要淘汰的缓存页多,导致淘汰过程中极有可能将需要频繁使用到的缓存页给淘汰了,而放进来的新数据却是使用率很低数据

MySQL确实没有直接使用LRU算法,而是在LRU算法上进行了优化 MySQL的优化思路就是

  • 对数据进行冷热分离,将LRU链表分成两部分

    • 一部分用来存放冷数据,也就是刚从磁盘读进来的数据
    • 另一部分用来存放热点数据,也就是经常被访问到数据
  • 当从磁盘读取数据页后,会先将数据页存放到LRU链表冷数据区的头部,

    • 如果这些缓存页在1秒之后被访问,那么就将缓存页移动到热数据区的头部:
    • 如果是1秒之内被访问,则不会移动,缓存页仍然处于冷数据区中
  • 淘汰时,首先淘汰冷数据区。

Page

image.png

页面结构

B+ Tree

image.png

事务引擎

事务引擎实现了数据库的ACID能力,这里以MySQL的InnoDB为例来介绍数据库内部是通过哪些技术来实现ACID:

  • Atomicity:InnoDB中通过undo日志实现了数据库的原子性,通过Undo Log,数据库可以回滚到事务开始的状态;
  • Isolation:通过Undo Log实现MVCC(多版本并发控制),降低读写冲突。
  • Durability:通过Redo Log(一种WAL实现方式)来保证事务在提交后一定能持久化到磁盘中。
  • Consistency:一致性本质上是一种业务层的限制。
Undo

image.png

lsolation与锁

image.png

lsolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。 如果多个并发事务访问同一行记录,就需要锁机制来保证了。 读写是否冲突?读写互不阻塞,MVCC机制。

lsolation与MVCC

image.png

每个数据不止一个版本,老版本记录在undo里面,新版本记录在数据页中,形成了新版本到老版本数据

持久化与Redo Log

image.png

  • 持久化:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
  • 方案一:由于数据可能是随机分布的,随机写数据要随机访问磁盘,只修改了10几个字节,但要修改整个页面,就涉及写放大问题
  • WAL:修改并不直接写入到数据库文件中,而是写入到另外一个称为WAL的文件中;如果事务失败,WAL中的记录会被忽略,撤销修改:如果事务成功,它将在随后的某个时间被写回到数据库文件中,提交修改。

MySQL的WAL(Write Ahead Log)在InnoDB中被称作redo log

优点:

  • 只记录增量变化,没有写放大。
  • Append only,没有随机IO。