RDBMS关系型数据库|青训营笔记

20 阅读4分钟

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

关键技术

客户端向数据库服务器发送一条SQL语句。服务器首先对SQL语句进行解析,然后对解析的结果进行路径优化,最后再执行查询。

image.png

解析器Paraser

解析器一般分为词法分析,语法分析,语义分析

image.png

  • 词法分析,抓取SQL的关键词,分成不同类型
  • 语法分析,将关键词构建成一个语法树,机器能够识别的
  • 语义分析,类型校验,表和列是否存在校验

优化器Optimizer

优化器用于优化SQL语句的执行路径

比如下图展示的表连接查询的顺序选择哪种 image.png

  • 基于规则的优化(RBO Rule Base Optimizer)
    • 条件简化
      • a = 5 and b > 5 ----> a = 5 and b > 5
      • a > 5 and a < b and b = 1 -----> false
    • 表连接优化
      • 总是小表先进行连接
    • Scan优化
      • 唯一索引
      • 普通索引
      • 全表扫描

索引是数据库管理系统中的一种数据结构,用于优化查询,更新过程

  • 基于代价的优化(CBO Cost Base Optimizer)
    • 代价可以是时间,IO,CPU,NET,MEM等。考虑整体并发的代价,而不是单条SQL查询的代价

执行器Executor

火山模型

image.png 每个Operator调用Next操作,访问下层Operator,获得下层Operator返回的一行数据,经过计算之后,将这行数据返回给上层

  • 优点:每个算子独立抽象实现,相互之间没有耦合,逻辑结构简单

  • 缺点:每计算一条数据由多次函数调用开销,导致CPU效率不高

向量化

image.png 每个Operator每次操作计算不再是一行数据,而是一批数据,计算完成后向上层返回一个Batch

  • 优点:函数调用次数降低为1/N
  • CPU cache命中率更高(因为CPU有预缓存的能力)
  • 可以利用CPU提供的SIMD(Single Instruction Multi Data计时)

编译执行:

image.png

把不同的算子组合到一起,将所有的操作封装到一个函数里面,函数调用的代价也能大幅度降低。但是用户的SQL千变万化,所以可以用到LLVM动态编译执行技术。

存储引擎 - InnoDB

内存部分和磁盘部分 image.png

In-Memory

  • Buffer Pool 缓冲池 image.png

image.png

image.png 通过LRU的方式淘汰内存空间中不常访问的数据。

  • Page

    • 变长字段列表:标志哪些字段是变长的,有多长
    • Null值标志位:标志哪些列数据是空的,哪些是有数据的
    • Header:delete_mask:此条数据是否被删除; next_record:下一条数据的位置; record_type:表示当前记录的类型
    • row_id:行ID
    • trx_id:当前行数据最新一一次操作是由哪个事务操作的
    • roll_ptr:回滚指针,指向Undo Log日志的row_id

image.png

image.png

  • B+ Tree

页面内:

页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录

从根到叶:

中间节点存储

页和页节点之间是双向链表的形式,可以实现范围查找 image.png

事务引擎-原子性和Undo Log日志

Undo Log是逻辑日志,记录的是数据的增量变化。利用Undo Log可以进行事务回滚,从而保证事务的原子性,同时也实现了多版本并发控制MVCC,解决读写冲突和一致性读的问题

image.png

事务引擎- 隔离性Isolation与锁

  • 读读是共享锁
  • 写写是排他锁
  • 读写是涉及到MVCC:MVCC的意义
    • 读写互不阻塞
    • 降低死锁概率
    • 实现一致性读
  • Undo Log在MVCC的作用
    • 每个事务都有一个单增的事务ID
    • 数据页的行记录中包含了DB_ROW_ID,DB_TRX_ID,DB_ROLL_PTR;
    • DB_ROLL_PTR 将数据行的所有快照记录都通过链表的结构串联起来

image.png

事务引擎-一致性Durability与Redo Log

如何保证事务结束后,对数据的修改永久的保存? 方案一:事务提交前页面写盘

随机IO,数据在磁盘上是随机分布的。随机访问代价比较大 写放大,数据管理的最小单元是Page,可能值修改了十几个字节,却要修改整个页面 方案二:WAL(Write-ahead logging)

redo log是物理日志,记录的是页面的变化,它的作用是保证事务持久化。如果数据写入磁盘前发生故障,重启MYSQL会根据Redo log重做