良许Linux教程网 干货合集 分布式数据库DDL的编译与执行

分布式数据库DDL的编译与执行

DDL 是数据定义语言,用于定义和管理 SQL 数据库中的所有对象的语言,常用的命令有:create,drop,alter 等。

DDL 是数据定义语言,用于定义和管理 SQL 数据库中的所有对象的语言,常用的命令有:create,drop,alter 等。通常来说,浪潮云溪数据库 DDL 语句的流程主要分为四个部分,分别是逻辑计划生成,物理计划生成,计划执行和 schemachange。本文主要介绍逻辑计划生成,物理计划生成和计划执行。

逻辑计划生成

逻辑计划生成主要是生成一个 planNode 逻辑计划节点,每一条 SQL 都会有自己的 planNode,以 create table 为例,该 SQL 生成的 planNode 中包含有 CREATETABLE statement 信息例如表名,有该表所属数据库的信息,还有该表的列的信息等。planNode 生成后将其记录到 planner 的 curplan(curplan 有当前计划的属性,包含抽象语法树,planNode,子查询计划等)里,主要流程如下图所示。

干货好文:分布式数据库DDL的编译与执行干货好文:分布式数据库DDL的编译与执行

以 create table 语句为例,构建逻辑计划主要是进行 memo 的构建以及 RBO 和 CBO 优化(memo 是用来存储查询计划森林的一种数据结构)。首先会初始化一个优化计划的上下文 optPlanningCtx,里面会初始化优化器并记录是否使用 memo cache 进行 memo 的缓存复用,而这也是 DDL 与 DML 语句之间的区别,DDL 语句不会复用 memo。

构建 memo 会调用 builder 的 build () 方法,对于不同的 DDL 语句,会调用不同的方法去构建逻辑计划。Create table 语句会调用 buildCreateTable, 构建 outScope,主要是生成语句的表达式 expr 记录在 outScope 里,最终记录到 memo 里面。而对于其他的 DDL 语句则会调用 tryBuildOpaque,然后通过 ConstructOpaqueDDL 函数构建 memo 的 expr。

Memo 构建完以后就是进行优化,通过 Optmize () 函数进入进行 RBO 和 CBO 优化,而 DDL 语句不会进行优化,这也是与 DML 语句的区别,DML 会将优化完的 memo 加入缓存。然后就是进行逻辑计划 planNode 的构建,DDL 语句中,create 语句会执行 buildCreateTable 进行 ConstructCreateTable 构建 createTableNode,而 drop 和 alter 语句则会执行 buildOpaque,通过 ConstructOpaque 返回所对应的 planNode,最后将构建好的 planNode 封装到 planTop 里面,并且如果是 DDL 语句会在 planTop 的 flags 里面置 planFlagIsDDL。

物理计划生成

逻辑计划生成后,就会根据逻辑计划生成物理计划,主要的流程如下图所示。

干货好文:分布式数据库DDL的编译与执行干货好文:分布式数据库DDL的编译与执行

在生成物理计划之前会先判断语句是否需要分布式执行,DDL 不会进行分布式执行,会生成一个本地的 PlanningCtx(PlanningCtx 包含在单个查询的整个规划过程中使用和更新的数据)。如果 SQL 语句有子句的话,则会调用 PlanAndRunSubqueries 函数先执行子句。DDL 语句会进入到 wrapPlan 进行物理计划的生成。在 wrapPlan 中会深度优先遍历 planNode 树,找到第一个支持 DistSQL processor 的 planNode 然后在该 planNode 上递归 DistSQL 优化,如果有等效的 DistSQL 处理器调用 createPlanForNode 生成物理计划。

函数首先判断当前 planNode 的类型,调用对应的函数为 planNode 创建物理计划 (如 indexJoinNode 会调用 createPlanForIndexJoin),DDL 则会递归调用 wrapPlan 将 planNode 包起来继续处理 (wrapPlan 只包装节点本身而不包括孩子节点)。然后,调用 shouldPlanTestMetadata 函数判断是否需要进行元数据处理,如果需要则添加相关信息)。然后再进行创建 planNodeToRowSource(该结构体),如果被包裹的 planNode 是 flow 中的第一个 node,且语句类型是 RowsAffected(返回受影响行的计数的语句)则可以使用 fast path,planNode 子树若支持 DistSQL 优化会在被优化后连接到 wrapper。返回 wrapper 后,为物理计划添加 LocalProcessor 和 LocalProcessorIndexes 的元素,LocalProcessors 数组包含了所有的 planNodeToRowSource,即被包裹的 planNode,记录物理计划的 ResultTypes。

每当添加新的 PhysicalPlan 时,都需要覆写 ResultRouters,我们将只需要一个 result router,由于 local processor 不是分布式的,确保 p.ResultRouters 只有一个元素,最后填充计划的 endpoints 就进入执行流程。

执行

执行过程的主要流程如下图所示。

干货好文:分布式数据库DDL的编译与执行干货好文:分布式数据库DDL的编译与执行

StartExec 是具体执行 planNode 的方法,根据构建的物理计划对表描述符进行操作。StartExec 会先对 commend 遍历(以 alter table 为例,commend 是一个表修改操作的切片),在遍历中获取集群版本信息,检查在当前版本中是否支持添加列的类型,若支持则为 true,反之报错;接着按照计划中的列定义信息生成列描述符,若添加的列是主键或含有唯一性约束,还会生成索引描述符,将这些描述符会包装成一个个 mutation 并添加到表描述符的 Mutations 字段里;然后根据表、mutation 等信息创建一个 job,job 也是通过系统表 system.jobs 进行维护,这个 job 是用来触发及跟踪 schema change 执行,接着将含有 mutations 的表描述通过 batch 更新到系统表 “descriptor” 里。

执行流程中最主要的结构体就是 batch,表描述符会存在 batch 里面,通过 writeTableDescToBatch 函数,在该函数里面,首先判断这个表如果不是一个新的表,需要将表的 version+1,然后会验证表描述符格式是否良好,调用 addUncommittedTable 函数,这允许事务在绕过表租赁机制的情况下查看自己的修改,最后是将表描述符的 KV 写入到 batch 里面。batch 构建完以后就执行 batchRequest。

在执行流程结束后,如果需要数据回填的话,则进入到 online schema change 流程回填数据然后写入系统表完成执行流程,如果不需要的话,则在执行算子的时候就将数据写入到系统表中完成执行流程。

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

邮箱地址不会被公开。 必填项已用*标注

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部