RDBMS 口水话|青训营笔记

111 阅读5分钟

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

本篇文章归档于 “第五届字节跳动青训营”,主要是为了完成和记录掘金的 “伴学笔记创作活动” 活动,如果你对我的其他文章感兴趣,可以去我的 专栏 中逛逛看有没有你想要的东西。

RDBMS 的发展

前 DBMS 时代:人工方式进行记录和管理 -> 文件系统进行记录和管理。

DBMS 时代:

  • 网状模型:直接描述现实世界,存取效率高,但结构复杂,用户不易使用,访问程序设计复杂;
  • 层次模型:结构简单,查询高效,可提供较好的完整性支撑,但无法表示 M:N 模型,插入、删除限制多,遍历子节点一定经过父节点,访问程序设计复杂;
  • 关系模型:实体之间用二维表结构表示,方便表示 M:N 关系,数据访问路径对用户透明,但关联查询效率不够高,关系必须规范化。

SQL(Structured Query Language)的特点:

  • 语法风格接近自然语言;且SQL语言语法简单,接近英语口语,因此容易学习,也容易使用;
  • 高度非过程化:关系数据模型的数据操纵语言是面向意图的语言,用 SQL 进行数据操作,用户只需提出”做什么”,而不必指明”怎么做”,这不但大大减轻了用户负担,而且有利于提高数据独立性;
  • 面向集合的操作方式:SQL采用集合操作方式,不仅查找结果可以是元组的集合,而且一次插入、删除、更新操作的对象也可以是元组的集合;
  • 语言简洁,易学易用:SQL功能极强,但由于设计巧妙,语言十分简洁,完成数据定义、数据操纵、数据控制的核心功能只用了9个动词: CREATE、ALTER、DROP、SELECT、INSERT、UPDATE、 DELETE、GRANT、REVOKE。

RDBMS 的关键技术

一条 SQL 的生命周期:

  • SQL 引擎
    • 查询解析:将文本解析成结构化数据,也就是抽象语法树(AST,Abstract Syntax Tree);
    • 查询优化:根据 AST 优化产生最优执行计划(Plan Tree);
    • 查询执行:根据查询计划,完成数据读取、处理、写入等操作;
  • 事务引擎:处理事务一致性、并发、读写隔离等;
  • 存储引擎:内存中的数据缓存区、数据文件、日志文件。

SQL 引擎

所有的代码在执行之前,都存在一个解析编译的过程,差异点无非在于是静态解析编译还是动态的。解析器(Parser)通常包含以下步骤:

  • 词法分析:将一条 SQL 语句对应的字符串分割为一个个 token,这些 token 可以简单分类;
  • 语法分析:把词法分析的结果转为语法树。根据 token 序列匹配不同的语法规则,匹配 SQL 语句中的关键字,最终输出一个结构化的数据结构;
  • 语义分析:对语法树中的信息进行合法性校验。

那对于数据库而言,一条 SQL 执行是需要代价的,对于用户而言,最直观的就是查询时间长短,但是在并发的情况下,就得考虑资源消耗了,因为一个用户的查询占用的资源多了,其他用户的资源就少了。因此,需要优化器(Optimizer)基于代价在不同的优化策略中做选择。

关于 SQL 的执行器,课件中提到了 3 种不同的模型:

  • 火山模型:每个 Operator 调用 Next 操作,访问下层 Operator;获得下层 Operator 返回的一行数据,经过计算之后,将这行数据返回给上层。
    • 优点:每个算子独立抽象实现,相互之间没有耦合,逻辑结构简单;
    • 缺点:每计算一条数据有 多次函数调用开销,导致CPU效率不高;
  • 向量化:每个 Operator 每次操作计算的不再是一行数据,而是 Batch(一批数据,N 行数据),计算完成后,向上层算子返回一个 Batch。
    • 优点:函数调用次数降低为1/N,CPU cache命中率更高,可以利用CPU提供的SIMD(Single Instruction Multi Data)机制;
  • 编译执行:代码生成之后数据库运行时仍然是一个 for 循环,只不过这个循环内部的代码从简单的一个虚函数调用 plan.next() 展开成了一系列具体的运算逻辑,这样数据就不用在各个 Operator 之间进行传递,而且有些数据还可以直接被存放在寄存器中,提升性能。
    • 改进:还可以利用 LLVM 动态编译执行技术,根据优化器产生的计划,动态的生成执行代码。

事务引擎