Skip to content

Latest commit

 

History

History
68 lines (39 loc) · 5.77 KB

3.database-system-architecture.md

File metadata and controls

68 lines (39 loc) · 5.77 KB

1.2 数据库系统架构

关系数据库大概分为三大块:存储、事务和 SQL。

  • 存储:相当于关系数据库的数据结构。

  • 事务:相当于关系数据库的算法。

  • SQL:相当于关系数据库操作的描述语言,其实就是相当于接口。SQL 在数据库实现中相当于接口的实现。

存储

存储在工业界基本上最常见的两种基础的数据结构:哈希表、B+ 树。

哈希表可以实现 O(1) 的这种计算,支持 put/get,哈希表 put/get 的性能非常快。唯一的缺陷是不支持范围 scan。

另外一种最常见的是 B+ 树,是今天关系数据库中用的最多的一种方式。B+ 树最大的优势它可以做范围 scan,并且它是一个平衡的二叉树,它的读、写、删除都非常的均衡,不会出现读性能特别好,写性能特别差或者读性能特别差,写性能特别好的情况,是一个非常均衡的算法。

最近一二十年出现了一个叫做 LSM-Tree 的基础数据结构。LSM-Tree 最大的特点就是它会更适合于写多读少的场景,其核心思想就是将离散的随机写请求都转换成批量的顺序写请求,大幅度减少随机写操作,提高写的性能。

数据库存储就是面向磁盘设计的一颗 B+ 树。

事务

事务相当于关系数据库的算法,是整个数据库中最难的部分。事务中有四个核心属性:

  • 原子性(Atomicity):事务操作要么全部成功,要么全部失败。即一旦事务出错,就回滚事务。

  • 一致性(Consistency):一个事务只能使数据库从一个一致的状态跳到另一个一致的状态,不能存在一个中间的状态。

  • 隔离性(Isolation):多个并发事务互相不影响,就如同多个事务串行执行一般。

  • 持久性(Duration):事务一旦提交成功对数据库的影响就是永久的。

SQL

SQL 就相当于关系数据库的操作语言,它其实就是一层基于关系代数的接口,并且非常有理论基础。在数据库内部有专门一个模块(SQL 引擎)来实现这一套接口。

执行流程

架构图

SQL 层

下表为 SQL 请求执行流程的步骤说明。

步骤 说明
Parser(词法/语法解析模块) 在收到用户发送的 SQL 请求串后,Parser 会做词法/语法分析,将字符串分成一个个的“单词”,并根据预先设定好的语法规则解析整个请求,将 SQL 请求字符串转换成带有语法结构信息的内存数据结构,称为语法树(Syntax Tree)。
Query result cache 直接对 SQL 进行硬解析,若发现命中,将直接绕过下面所有过程,返回结果给应用方。
Resolver(语义解析模块) Resolver 将生成的语法树转换为带有数据库语义信息的内部数据结构。在这一过程中,Resolver 将根据数据库元信息将 SQL 请求中的 Token 翻译成对应的对象(例如库、表、列、索引等),生成的数据结构叫做 Statement Tree。
Plan Cache(执行计划缓存模块) 执行计划缓存模块会将该 SQL 第一次生成的执行计划缓存在内存中,后续的执行可以反复执行这个计划,避免了重复查询优化的过程。 Resolver 中生成的 Statement Tree 将会与该模块中的执行计划做匹配,若匹配命中,Plan Cache 直接将其物理执行计划发送到 Executor 中进行执行。
Transfomer(逻辑改写模块) 分析用户 SQL 的语义,并根据内部的规则或代价模型,将用户 SQL 改写为与之等价的其他形式,并将其提供给后续的优化器做进一步的优化。Transformer 的工作方式是在原 Statement Tree 上做等价变换,变换的结果仍然是一棵 Statement Tree。
Optimizer(优化器) 优化器是整个 SQL 请求优化的核心,其作用是为 SQL 请求生成最佳的执行计划。在优化过程中,优化器需要综合考虑 SQL 请求的语义、对象数据特征、对象物理分布等多方面因素,解决访问路径选择、联接顺序选择、联接算法选择、分布式计划生成等多个核心问题,最终选择一个对应该 SQL 的最佳执行计划。
Code Generator(代码生成器) 将多个算子合并到一起,生成一个更高效的算子。
Executor(执行器) 启动 SQL 的执行过程。
  • 对于本地执行计划,Executor 会简单的从执行计划的顶端的算子开始调用,根据算子自身的逻辑完成整个执行的过程,并返回执行结果。
  • 对于远程或分布式计划,将执行树分成多个可以调度的子计划,并通过 RPC 将其发送给相关的节点去执行。

事务层和存储层

事务层和存储层在真实的工业界并没有上图中切分的那么干净,很多时候其实是相互掺杂,相互交错在一起。

事务管理器里面可以分为两个部分。

  1. 日志与恢复,所有的 SQL 在对磁盘进行操作的时候都会写一些日志,比如物理日志,逻辑日志,并且会提供一定的恢复功能,该部分负责事务的持久性。

  2. 并发控制,即怎么来控制对数据的事务,并发控制包括锁和 MVCC。并发控制负责保证事务的原子性和孤立性。

在存储层存在 Buffer Pool(缓冲池),所以不会直接从底层的磁盘中将数据提取出来。很多时候是通过 Buffer Pool 查询 Catalog,然后从 Catalog 中拿到所有的元数据信息,之后再发请求给存储管理器,由存储管理器最后发送到存储,然后从存储中将数据拿取出来。