CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生

2024年 5月 7日 33.6k 0

高手云集,群英荟萃。

2022年3月19日 CSDN 数据库沙龙上,众多技术专家汇集在数据库线上 Meetup 直播现场,来自 OceanBase 技术专家田逸飞(花名:义博)为大家精彩讲述了 OceanBase SQL 的一生。

本次分享从一条 SQL 被数据库接收开始,一直到执行结束,讲述了数据库中的整体执行流程,以及了解 OceanBase 如何让同一类 SQL 共享执行计划,通过这条SQL的一生,帮助大家更好的了解和掌握 SQL 执行流程和计划缓存两大模块。

一、SQL 执行流程

1.SQL 执行流程介绍

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-1

从图中我们可以看到,当用户从 SQL 发送到 OBServer 后,会先由 OBServer 对其进行快速参数化,参数化后的 SQL 进入 Plan Cache 尝试命中计划缓存。当找到一个可以使用的计划,则直接将计划交由 SQL 的执行引擎去执行,并将执行完成后的结果返回给用户;如果没有找到可以使用的计划,则会重新为此 SQL 生成计划,完整地执行 SQL 的Parser、Resolver、Transformer、Optimizer、Code Generator 解析流程,然后生成一个可用的物理执行计划,并交由执行引擎执行,同时此计划会被加入到计划缓存,以便后续的 SQL 重新使用,详见下图。

2.查询改写

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-2

如下图所示,流程中的 Parser 主要负责语法词法的解析,它会将用户输入的 SQL 基于 lax 和 yacc 生成一个 Parse Node Tree,如下图右侧所示,它将用户的 SQL 拆成了一个树状结构,同时做了一些语法解析。

3.语义分析

Resolver 负责对 Parse Node Tree 做语义的分析,主要包括语句的解析、中缀表达式的生成、表达式的类型推导等,并最终将其转化成 OceanBase 在代码中更易于操作的数据结构

4.查询改写

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-3

Transformer 会在保证 SQL 执行结果相同并且正确的情况下对 SQL 做等价变换。目前在 OceanBase 中存在两类改写。

  • 基于规则的改写,这一类改写总是会把 SQL 向好的方向改写,比如 join 连接消除改写
  • 基于代价的改写,这一类改写发生后 SQL 的性能可能变得更好或者更差。对于这一类的改写,会分别计算发生改写 SQL 和不发生改写的代价。在比较之后,对于那些发生改写后代价低时 OceanBase 选择改写;而发生改写 SQL 后代价更高的情况,则不去选择改写。

 

5. 查询优化

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-4

在 Transformer 做完等价改写之后,将改写后的 SQL移交至 Optimizer ,也就是查询优化模块中,由 Optimizer 继续生成逻辑计划。Optimizer 会对用户的 SQL 生成一组可选的逻辑计划,从这些所有的逻辑计划中选出一个优化器所认为的最优计划,详见上图。

 

在这个过程中,Optimizer 会结合代价模型和统计信息,做基表路径、连接顺序、连接算法的选择以及分布式计划的生成等。并且在做出这些选择的过程中,Optimizer 还会有一些基于规则的剪枝和 Skyline 剪枝的优化,通过这些剪枝规则减少优化过程中路径的数量,降低优化的复杂度,从而提升优化速度。

 

 

6 .代码生成

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-5

在 Optimizer 模块完成后,便得到了 SQL 的逻辑计划,而这个逻辑计划被移交 Code Generator 做代码生成,因为此时的逻辑执行计划不能被直接执行。所以 Code Generator 需要将逻辑的执行计划翻译,生成执行引擎可识别、可执行的物理执行计划。也就是说,Code Generator在这里所做的事情其实就是单纯的对逻辑执行计划做一个转换,包括将逻辑执行计划中的逻辑算子转换成物理算子。

经过 Code Generator 这个步骤,我们得到可以实际执行的物理执行计划,而这个物理执行计划也会被交由 Executor ,也就是我们的执行引擎去执行。

7. 执行引擎

在 OceanBase 中的执行引擎使用的是火山模型。火山模型在数据库中非常常见,是经典的数据执行模型。除此之外,OceanBase 的执行引擎还提供了并行执行框架,比如说当 CPU 资源容量足够多时,用户可通过开启并行机制来提高 SQL 的执行性能。

二、计划缓存

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-6

在将计划缓存之前,先介绍一下计划缓存的两种匹配模式:

Foece 模式和 Exact 模式

1.Force 模式

这是 OceanBase 默认的匹配模式。 Force 模式下,首先会对 SQL 里面的常量进行参数化,再对参数化后的计划进行匹配。什么是参数化呢?如上图右侧 SQL 语句, select c1,c2 from t1 where c1=1,这里的1 是一个常量。参数化就是将常量替换成一个通配符“?”。所以参数化之后,这条 SQL 就变成了 select c1,c2 from t1 where c1=?。

参数化之后,文本与此条 SQL 一样的 SQL 都可以共享一个计划。比如这里 where c1=1、c1=2、c1=3的语句都可以共用同一个执行计划。但它的不足之处在于 SQL 命中的计划可能并不是一个最优的执行计划。

依然以上述 SQL 为例,假设对于 t1 中,c1=1 的值占了1%,c1=0 的值占了99%,即表里的c1 只有 1 和 0 两个取值。

假设一开始计划缓存是空,先来了一个 c1=1 的 SQL,就会用这条 SQL 去生成计划。如果c1=1 的过滤性非常好的,则会选一个走 c1 索引的计划,相当于在 c1 的索引上做一次扫描,然后做索引回表,并将计划缓存到计划缓存中。但是如果之后来了一个 c1=0 的 SQL,那么它就会命中刚刚生成的计划走索引扫描。但是对于 c1=0的条件,索引其实不是最优的,

因为它不能过滤掉大量数据。索引扫描完成后它还有 99% 的数据要做索引回表。在这种场景下,索引往往不如基表扫描快。

2.Exact 模式

Exact模式下,做计划匹配的时候不会做参数化,而是直接用原始的 SQL 去做匹配,匹配的时候要求 SQL 的文本完全相同。比如大小写、空格的数量以及参数都要相同才能共享计划。

它的优点在于不同的参数都能选到自己最优的计划。不足之处也非常明显——计划的命中率非常低。比如通过主键去查找表里某一行具体的数据,主键在表中的每一个值都是不同的,也就意味着它们都无法共享计划,每一个主键值都要重新生成一次计划,这就导致计划的命中率非常低。而且大量的计划会导致计划缓存的内存会大幅膨胀。

 

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-7

上图展示了一些计划共享的例子。

第一组 SQL 参数化之后都会变成 select c1,c2 from t1 where c1=? and c2 =?。它们参数化后的 SQL 文本是相同的,因此可以共享计划。

 

第二组 SQL 参数化之后变成了select c1,c2 from t1 where c1=? order by ?。

但实际上它们的语义是不一样的,第一条 order by 1,意味着要对 select 里的第一列做排序,而第二条意味着要对 s

elect 里的第二列做排序。如果它们共享计划,两个结果一定会出现问题。

为了防止这样错误的共享计划,OceanBase引入了额外的约束机制。比如对于第一条 SQL ,要求 order by=1 的时候才能使用它生成的计划,同理对于第二条 SQL 会要求 order by=2 的时候才能使用它生成的计划。

第三组 SQL 参数化之后会变成 select c1,c2 from t1 where c1=? and ? = ?。而它在 OceanBase 中也是无法共享计划的。因为1 = 1是一个恒 true的条件,而 1 = 2 是一个恒 false 的条件。对于这种恒 true、恒 false 的条件,OceanBase 在改写优化的过程中会对其做一些特殊处理,简化这些计划的生成过程和生成的计划。一旦不同的恒 true、恒 false 条件共享了计划,也会导致一些结果错误。

 

对于上述场景, OceanBase 也会抽取出约束。比如对于第一条 SQL,它会要求第二个参数等于第三个参数的计算结果是 true 的时候才能共享这条 SQL 产生生成的计划;对于第二条 SQL,它会要求第二个参数等于第三个参数的计算结果是 false 的时候才能共享第二条 SQL 产生的计划。

第四组 SQL 的问题在于 select 的大小写不同,因此也不能共享计划。

 

3.SQL 执行计划获取过程

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-8

这里的图片内容跟第一部分几乎完全相同。对于一个 SQL 请求,OceanBase 会对这条 SQL 做一次快速参数化,并用参数化后的 SQL 到计划缓存中匹配执行计划。这里存在能匹配到计划和匹配不到计划两种情况。如果匹配到就去执行;而匹配不到则将走完一个完整 SQL 执行流程,先在 Parser 中做词法语法解析。具体流程是:SQL 先通过 Parser 做语法词法解析,然后做一次普通参数化,最后再做剩下的 Resolver、Transformer、Optimizer 等一系列过程。

 

4.快速参数化和普通参数化区别

快速参数化

快速参数化的功能:通过语法分析快速将 SQL 中常量值替换为通配符的问号。

快速参数化只依赖词法分析即可直接基于 SQL 文本做参数化,对 Parser 的依赖小,参数化效率高。

在参数化的过程中 OceanBase 会记录当前 SQL 的参数信息,用于计划匹配时检查是否满足约束。

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-9

 

普通参数化

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-10

普通参数化是基于 Parser 的结果进行参数化的过程。在 Parser 之后我们已经得到了 SQL 完整的语法词法树,也就获得了 SQL 的语义信息。在这个基础上我们做参数化可以进行一些额外的操作,例如约束的抽取。当我们对上图中的语法词法树进行参数化时,会发现 order by 后是一个常量,这个时候我们就会抽取约束,要求 order by 后的参数必须为1时才能共享这条 SQL 生成的计划。

5.计划更新

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-11

生成的物理执行计划并非一成不变,在某个时间点生成的计划只能表示,

一条 SQL 在特定时间点最优的计划。但在数据库中,表的结构、表中数据量、表中数据值的分布都可能会发生变化,在各种因素的不断变化中,不能保证在某一个时间点生成的计划永远是最优的。所以计划一定需要在合适的时机更新,从而保证这个计划相对来说是最优计划。

OceanBase 计划更新场景

  • 执行计划依赖对象的 Scheme 发生变化

比如数据表T1,在T1上新建一个索引,建立索引的动作会导致T1表 schema 的版本号被推高,而当检测到schema 版本号推高时,计划缓存中所有涉及到T1表的计划全部失效。如果此时一条新的 SQL 完全依赖这个数据表T1 ,就会重新生成计划。因此这时新计划极可能用新建索引做出更好的优化。

  • 统计信息发生改变

当统计信息发生变化时,可以利用更新的统计信息重新生成计划。比如当列的直方图、NDV值、最大最小值更新时,优化器可以使用这些新的统计信息去生成更好的计划。

  • 执行反馈需要更新计划

通过执行反馈发现当前的执行计划,相比于它生成计划时的性能更差。这时即可将此计划完全淘汰,重新生成计划。

 

以上就是关于在 OceanBase 中 SQL 执行流程和计划缓存的所有内容。非常期待和欢迎大家到 OceanBase 开源社区参与讨论、交流和互动,请扫描以下二维码,快速与我们联系。

CSDN 数据库Meetup|OceanBase 技术专家讲述 SQL 的一生-12

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论