openLooKeng postgreSQL connector for update/delete table

相关背景

需求

当前openLooKeng postgreSQL connector不支持对数据表的update和delete操作,本文拟在openLooKeng框架的基础上,开发postgreSQL connector支持update/delete操作的代码。

openLooKeng语句执行流程

一条SQL语句的执行的整体流程如下图所示:
在这里插入图片描述
这里面主要涉及到两种类型的节点,分别为Coordinator和Worker节点。

  • Coordinator 节点是用来解析语句,执行计划分析和管理 openLooKeng 的 Worker 节点,同时Coordinator 跟踪每个 Work 的活动情况并协调查询语句的执行。Coordinator 为每个查询建立模型,模型包含多个Stage,每个Stage再转为Task 分发到不同的 Worker 上执行。
  • Worker 是负责执行任务和处理数据。Worker 从 Connector 获取数据。Worker 之间会交换中间数据。Coordinator 是负责从 Worker 获取结果并返回最终结果给 Client。

具体步骤为:

  1. 客户端通过协议发送一条查询语句给openLooKeng集群的Coordinator;
  2. Coordinator接手到客户端传送到的查询语句,对语句进行解析、生成查询执行计划,根据查询执行计划一次生成sqlQueryExecution->sqlStageExecution->HttpRemoteTask;
  3. Coordinator将每个task分发到所需要处理的数据所在的Worker节点上执行;
  4. Task通过Connector从数据源中读取数据,并执行Source Stage的task;
  5. 处于下游的Stage中的task会读取上游Stage产生的输出结果,并在该Stage的每个task所处的Worker的内存中进行后续处理;
  6. Coordinator从发布的task后,持续地从Singe Stage中的task获取结果,并将结果缓存到buffer中,知道查询结束;
  7. Client从提交查询之后,会持续地从Coordinator获取本次查询的计算结果,知道获得所有的计算结果。

openLooKeng内核调用

openLooKeng的多源查询能力是通过 Connector 机制来实现的。其中MySQL、postgreSQL等Connector是主要是通过presto-base-jdbc中的代码来实现对SQL等数据源的读写。

openLookeng内核调用
其中openLooKeng-spi中主要定义了一些公共接口,供openLooKeng-main中的代码进行调用。

openLooKeng-base-jdbc是数据库连接器的公共模块,对openLooKeng-main进行了实现和补充。其代码经过编译后,会对应加载到mysql-plugin等插件中,实现mysql对数据源的访问功能。base-jdbc本身自己不会编译单独的插件。

通过断点调试,对openLooKeng接受一条update SQL语句的函数栈调用流程进行梳理总结,如下图所示。
在这里插入图片描述

结合源码分析,发现一条update语句在connector jdbc中的执行流程为beginUpdate()->getConnection()->buildUpdateSql()->setUpdateSql()->finishUpdate()。在这个过程中需要一个字段作为行标识符来表示数据行。

其中buildUpdateSql将openLooKeng传入的update SQL语句转换为connector更新时的预编译语句,这里用到获取的行标识符作为where的筛选条件;setUpdateSql作用是以where条件对数据行进行更新。

因此若想要实现postgreSQL conncetor的update/delete table功能,我们需要重写上述函数即可完成。

代码实现

方案设计及论证

通过前期的调研,共形成了以主键为标识符和以ctid字段为标识符的两种开发方案。

方案一:以主键为标识符

主键的定义为:表中经常有一个列或列的组合,其值能唯一地标识表中的每一行。由定义可知,主键对应到一张数据表中会设计到多种场景,分别为:没有主键、单字段主键以及多字段组合成的复合主键,因此需要考虑的情况较多。

方案二:以ctid字段为标识符

ctid表示数据行在它所处的表内的物理位置,ctid字段的类型是tid。尽管ctid可以快速定位数据行,每次vacuum full之后,数据行在块内的物理位置就会移动,即ctid会发生变化,所以ctid不能作为长期的行标识符。因此如果要以ctid字段为标识符进行代码开发,需首先验证ctid在同一事务中进行update/delete操作是否会发生变化。

ctid在同一事务中的变化情况

为了验证ctid字段能否用于postgreSQL的update/delete操作,我们分别在单线程和多线程的情况下去验证ctid在同一事务和不同事务的变化情况。

单线程

通过jdbc模拟了单线程,在线程中对数据表进行update操作,分别查询update前后的信息,观察ctid的变化情况。
在这里插入图片描述
autocommit=false时,结果显示ctid未发生变化:

autocommit=true时,结果显示ctid发生变化:
在这里插入图片描述

多线程

同理,通过jdbc模拟了两个线程,在两个线程中分别对数据表进行update操作,分别查询update前后的信息,观察ctid的变化情况。

autocommit=false时,结果显示ctid未发生变化:
在这里插入图片描述
autocommit=true时,结果显示ctid发生变化:
在这里插入图片描述
由验证实验结果来看,在同一事务中,update未提交前或者回滚之后ctid是不变的。

开发方案选择

综合对比两种方案,其优缺点对比如下:

方案优点缺点
主键1、每一数据行的标识符能够始终保持不变。1、场景复杂,需考虑数据表无主键、单字段主键及多字段复合主键等多种情况;
2、不太适合现有openLooKeng下推框架。
ctid字段1、ctid性质类似与rowid,代码开发可借鉴性较高。1、需考虑在同一事务中对数据行进行update/delete。

综上所述,本文拟采用以ctid字段为行标识符进行代码开发。

ctid字段为行标识符的代码开发

autocommit设置为false,即保证能在同一事务中进行操作,ctid是可以保证唯一性的。而PostgreSql的继承关系为
在这里插入图片描述
因此我们的主要开发重点在于重写beginUpdate()-> getConnection()-> buildUpdateSql-> setUpdateSql ->finishUpdate()

**getUpdateRowIdColumnHandle()**用于获取行标识符
在这里插入图片描述
beginUpdate()
在这里插入图片描述
getConnection重写BaseJdbcClient该方法,用于将只读模式设为false,以便于进行更新操作
在这里插入图片描述
buildUpdateSql将openLooKeng传入的update SQL语句转换为oracle更新时的预编译语句,其内部调用关系为

	buildUpdateSql()
		buildRemoteSchemaTableName()
		getColumnNameFromDataSource()
			getColumnNameMap()

其中buildRemoteSchemaTableName()获取数据表名,getColumnNameFromDataSource()用于从源数据中获取要更新的字段名,getColumnNameMap()用于构建字段名的映射关系,将原始字段统一转换为小写字母。具体实现如下图所示:
在这里插入图片描述
setUpdateSql是以where条件对数据行进行更新,其内部调用关系为

	setUpdateSql()
		setStatement()

其中setStatement()用于对需要更新的字段根据数据类型进行赋值。具体实现如下图所示:
在这里插入图片描述

到此,我们完成了postgreSQL connector的update功能代码,而delete功能代码与此具有很大的相似性,此处不做展开讲述,具体可参考PostgreSqlClient实现

功能展示

此处我们简单演示postgreSQL connector的update/delete特性。首先需对代码进行编译,运行**mvn clean install -DskipTests -T 1C即可,编译完成之后,拷贝hetu-server-1.5.0-SNAPSHOT文件夹及hetu-cli-1.50-SNAPSHOT-executable.jar包。紧接着相关配置可参考社区文档。

在web界面输入ip及端口号,显示
在这里插入图片描述
数据表已经建好,具体实例为
在这里插入图片描述
针对update,执行语句及结果包括

功能点SQL结果
boolean表达式update infomation set name = ‘Kitty’, age = 26, birthday = date’1995-08-16’ where id = 1;
update infomation set name = ‘Jane’, sex = ‘2’ where score = ‘good’;
update infomation set score = ‘qualified’ where salary = 10000.00;
update infomationa set age = age + 1, birthday = date’1998-08-16’ where age = 22;
update infomation setT salary = 36000 where birthday = date’1996-08-14’;
update infomation set score = ‘bad’, birthday = date’1995-10-16’ where name = ‘Jane’;
success
子查询update infomation set age=age+1 where salary=(select avg(salary) from data);
update infomation set salary=salary+1000 where age in (select age from data where birthday between date’1993-09-01’ and date’1997-08-31’);
success

针对delete,执行语句及结果包括

功能点SQL结果
boolean语句delete from infomation where name = ‘Bob’;
delete from infomation where birthday = date’1996-08-14’;
delete from infomation where salary = 15000;
success
子查询"delete from infomation where salary<(select avg(salary) from data);
delete from infomation set salary=salary+1000 where age in (select age from data where birthday between date’1993-09-01’ and date’1997-08-31’);
success
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值