暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

亚信安慧AntDB-M 只读事务提交优化

tocata 2024-09-27
191


导读:

在新一代信息技术创新应用的大背景下,为了降低用户使用成本、加快改造速度,很多数据库产品都在做Oracle兼容性适配。AntDB作为一款成熟、稳定的国产数据库,高度兼容Oracle语法。本文将主要介绍AntDB数据库基于操作符的隐式转换及其设计原理,包括Oracle兼容模式下基于操作符的隐式转换。


一、AntDB的类型转换概述


AntDB的类型转换主要分为显示转换和隐式转换。


1. 显示转换


显示转换是指明确地使用类型转换函数将一个数据类型转换成另一个数据类型。在AntDB中使用CAST函数或者使用类型强转(::)进行显示转换。


2. 隐式转换


隐式转换是指数据库在执行查询时(SQL解析阶段)自动进行的类型转换,而不需要显示指定类型转换函数。在AntDB的SQL解析器中,主要有以下情形需要做隐式类型转换。


函数调用

AntDB的大部分类型建立在一套丰富的函数上,函数可以有一个或多个。由于AntDB允许函数重载,所以函数名自身并不唯一地标识需要被调用的函数,解析器必须根据提供的参数类型选择正确的函数。


操作符

AntDB支持带有前缀或后缀的一元(单目)操作符表达式,也支持二元(两个参数)操作符。与函数类似,操作符也可以被重载,因此操作符的选择也跟参数类型息息相关。


值存储

INSERT和UPDATE语句可以将表达式的结果存放到表中,而表达式结果的类型必须和目标列的类型一致(或者可以被转换成一致)。


UNION、CASE和相关结构

因为来自一个联合(UNION)的各个SELECT语句中的查询结果需要汇总到一个列中集中显示,所以每个SELECT子句的结果类型必须能相互匹配并被转换成一个统一的集合。


类似的,一个CASE结构包含多个条件表达式,但是输出结果只能是一种类型,因此多个条件表达式必须被转换成一种公共的类型,这样CASE语句作为整体才有一种已知的输出类型。同样的要求也存在于ARRAY[]结构以及GREATEST和LEAST函数中。



二、操作符


AntDB中操作符可以分为一元操作符和二元操作符。一元操作符只操作一个操作数,例如正负号、按位取反等。


以下是一元操作符的一些示例:


  • 正号(+):返回操作数的正值。

  • 符号(-):返回操作符的负值。

  • 按位取反(~):对操作符的二进制进行按位取反。

二元操作符操作两个操作数,列如加、减、乘、除法,比较操作符等。以下是二元操作符的一些示例:


  • 加法(+):返回两个操作数的和。

  • 减法(-):返回两个操作数的差。

  • 大于(>):比较两个操作数,如果第一个操作数大于第二个操作数,则返回true,否则返回false。

  • 小于(<):比较两个操作数,如果第一个操作数小于第二个操作数,则返回true,否则返回false。


在SQL中操作符的使用是非常常见和重要的,很多数据的计算和筛选都依赖操作符的使用,尤其是二元操作符。


1. 基于操作符的隐式转换


在SQL解析阶段会对操作符表达式进行解析,并选择操作数的类型。因为操作符的功能最终是通过函数实现的,操作数则是函数对应的参数,那么在SQL解析阶段对操作符表达式的解析,最根本的目的是根据操作符名称和操作数类型。选择最正确最合适的函数,并将操作数类型,转换成函数可以接收的参数类型。


(一)操作符类型选择


  1. 解析操作符的左右表达式(左右输入参数)

    • 分别解析操作符的左右表达式,解析完成后将获得左右操作数的类型。

  2. 从系统表pg_operator中选出要考虑的操作符(模糊匹配)

    • 如果使用了一个不带模式限定的操作符名(常见情况),则操作符被认为是那些在当前search_path中可见并有匹配的名字和参数个数的操作符。

    • 如果指定了模式限定的操作符名,则只考虑指定模式中的操作符。

    • 如果search_path中不同模式下找到多个有相同参数类型的操作符,则只考虑最早出现在search_path中的那一个。

  3. 精确找出一个正好接收输入参数(左右操作数)类型的操作符

    • 如果找到,则使用之;否则,进行下一步寻找最优匹配。

  4. 处理未知类型(unknown)输入参数的情况

    • 如果一个二元操作符中的一个输入参数是unknown类型,则在精确查找时假设其与另一个参数类型相同。

    • 对于涉及两个unknown类型的输入参数或者一个unknown类型的一元操作符,在这一步将永远找不到一个精确匹配。

    • 如果一个二元操作符中的一个输入参数是unknown类型且另一个是一种域(domain)类型,查找匹配时会看看是否有一个操作符正好在左右两边都接收该域的基类型,如果有则匹配成功。

  5. 寻找最优匹配的操作符

    • 如果未找到精确匹配的操作符,将根据以下原则选择最优匹配: ①. 排除不匹配且无法转换的候选操作符,unknown类型视为可转换。 ②. 将域类型视为其基类型。 ③. 选择左右参数类型最匹配的操作符。 ④. 优先考虑首选转换类型。

  6. 处理未知类型(unknown)输入参数

    • 尝试为unknown类型找到合适的类型分类,若候选操作符参数类型相同,则假定unknown类型也相同。

  7. 最终筛选

    • 若unknown参数与已知参数类型一致,选择能接受该类型的操作符。





3.2 Oracle兼容模式下的操作符类型选择

Oracle兼容模式下的操作符类型选择整体上套用了非兼容模式下的选择框架,只不过针对Oracle特有的数据类型和操作符追加了一些特殊处理。这里有以下几个重要前提:

  • Oralce兼容模式下的操作符实现函数已实现,且相关元数据追加到pg_operator系统表

  • Oracle兼容模式下特有的数据类型已经实现,且能和非兼容模式下的某个或某些类型可以相互转换。

上述两个前提条件的实现方法和实现原理本文不会详细讨论。接下来本文重点说明实现Oracle兼容模式下的操作符类型选择的实现原理。

  1. 增加系统表ora_convert,用来存放oracle操作符的参数类型转换规则。

  2. 在“3.1操作符类型选择“章节的步骤2之前,追加以下处理

如果开启了Oracle兼容模式,那么在ora_convert系统表检索匹配的操作符(根据cvtname和cvtfrom进行匹配检索)。如果找到匹配的记录,则将左右表达式类型转换成cvtto列中对应的类型。

  1. 接下来的处理与3.1操作符类型选择“章节的步骤基本相同。

4 总结

隐式转换对用户是透明的,但在数据库内部确是非常重要的,因为这会涉及到SQL的执行效率(例如:不恰当的类型隐转可能使索引失效)。在实现Oracle兼容模式时,最好基于现有的框架进行设计,而不是单独设计一套框架。


一、事务操作介绍
数据库系统一般有三种开启和提交事务方法:
  1. 配置autocommit=1时,隐式开启事务,每执行一条DML的SQL语句,数据库系统会隐式的自动执行commit逻辑提交事务,不需要用户输入commit执行提交。
  2. 配置autocommit=0时,隐式开启事务,随后执行的DML的SQL语句都在同一个事务内,直到用户输入commit执行提交。
  3. 用户输入BEGIN/START TRANSACTION,显式开启事务,随后执行的DML的SQL语句都在同一个事务内,直到用户输入commit执行提交。
在事务开启和提交过程中执行的DML的SQL语句,申请到的表意向锁资源,根据2PL协议会一直持有直到事务提交或回滚才会释放。
如果用户使用autocommit=0或begin这两种开启事务,执行DML的SQL语句,未输入commit提交事务,在这期间,同时另一个用户执行相同表的DDL语句,如果开启事务和执行DML的语句是发生在主副本上,DDL请求会等待超时后失败;如果开启事务和执行DML语句发生在备副本上,这时DDL语句在主副本上是成功的,DDL语句通过复制协议同步到备副本上执行,会等待锁超时后失败,导致后续通过复制协议同步过来数据无法继续应用到备副本上,副本间数据同步中断。
二、 现有空闲长事务中止方案
AntDB-M起初通过配置事务超时间来解决长时间空闲事务未提交带来的事务占用资源未释放的问题,如果空闲事务超时,数据库系统会自动中止事务,执行回滚操作,释放事务资源。
基于空闲事务超时,释放事务资源的方案,有以下缺点:
  1. 超时时间配置值不好评估,如果确实有个别应用处理产生的长事务会超过空闲事务超时时间,会影响正常应用流程;
  2. 副本数据同步实时性不足,数据丢失风险,如果在在备副本上空闲事务超时时间范围内发生的DDL等待失败,副本数据同步中断;如果在DDL等待成功(DDL等锁时间大于空闲事务超时时间),但备副本同步落后。

三、 只读事务提交优化方案
AntDB-M后续做了进一步的优化,对于只读查询事务长时间未提交,并且数据库的隔离级别是读已提交(Read Committed)时,自动提交查询操作,立即释放事务资源,使并发的DDL执行成功,副本数据同步不中断,保证数据库集群稳定。
在数据库隔离级别为读已提交(Read Committed)时,且autocommit=0的场景下:
  1. 如果事务前序的只读查询操作的DML,每执行一条只读查询操作的DML后,系统自动提交;
  2. 如果事务执行过写操作的DML,之后的再执行只读查询或写操作的DML,不执行自动提交;
只读查询操作的DML有:SELECT语句(不带FOR UPDATE);
写操作的DML有:INSERT、UPDATE、DELETE、SELECT FOR UPDATE;
对于显式BEGIN/START TRANSACTION开始的事务,因为是显式开启事务,认为用户是自知的,不使用此方案。
此方案限定在读已提交(Read Committed)隔离级别,不会影响查询结果的正确性。
四、只读事务提交优化效果演示
演示环境使用Read-Committed隔离级别和autocommit=0。
如图1所示,在set allow_readonly_autocommit=off,关闭只读事务提交优化,只读SELECT操作在没有提交事务时会保留一把表意向锁,提交后锁释放掉。
图1:优化前执行效果
如图2所示,在set allow_readonly_autocommit=on,开启只读事务提交优化,只读SELECT操作在事务未提交时也不会持有表意向锁,在UPDATE写操作后的只读SELECT操作不会释放锁,提交后所有锁都释放。
图2:优化后执行效果
由此可见,该优化方案可解决备副本上因为只读事务查询操作长时间不提交导致DDL执行阻塞或失败问题,避免了数据库集群副本间数据同步落后或中断,提高了AntDB-M数据库集群的稳定性。


关于亚信安慧AntDB数据库
AntDB数据库始于2008年,在运营商的核心系统上,服务国内24个省市自治区的数亿用户,具备高性能、弹性扩展、高可靠等产品特性,峰值每秒可处理百万笔通信核心交易,保障系统持续稳定运行超十年,并在通信、金融、交通、能源、物联网等行业成功商用落地。


「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论