数据库变更时,OceanBase如何自动生成回滚 SQL

news2024/12/23 18:25:14

背景

在开发中,数据的变更与维护工作一般较频繁。当我们执行数据库的DML操作时,必须谨慎考虑变更对数据可能产生的后果,以及变更是否能够顺利执行。若出现意外数据丢失、操作失误或语法错误等情况,我们必须迅速将数据库恢复到变更之前的状态,以确保数据的一致性和完整性。然而,回滚操作通常需要开发人员手动编写回滚SQL脚本,这不仅繁琐复杂,而且极易出错。

为了解决这个问题,ODC(OceanBase Developer Center)V4.2.0支持在执行数据库变更任务时自动生成备份回滚 SQL 以提高开发效率、减少错误率,保证数据的一致性和完整性。当单条误操作 SQL 受影响的数据量在10万以内时,您可使用该方法进行数据恢复。

功能体验

  1. 点击「工单」-> 「新建工单」-> 「数据库变更」,在 ODC 的「新建数据库变更」页面中,勾选「生成备份回滚方案」并填写工单详情。

  1. 点击「新建」后待工单审批通过。
  2. ODC 会根据您填写的「SQL内容」生成对应的「备份回滚方案」,您可以在工单的「任务详情」中的「任务信息」页面点击「下载备份回滚方案」以下载 ODC 生成的「备份回滚方案」文件:

也可以在工单「任务详情」中的「任务流程」中点击「下载备份回滚方案」以下载该文件。

  1. 如需回滚该工单您可以在此工单的「任务详情」页面的右下脚点击「回滚」重新发起数据库变更工单以申请回滚操作。发起回滚工单后您可以在此工单的「任务详情」中的「回滚工单」页面查看此工单关联的回滚工单。

例如,针对 「SQL内容」为以下的数据库变更任务:

update t2 set c2=11 where c1=1;
update tab2 set c2=11 where id=1;

生成的「备份回滚方案」示例如下:

/* 
[SQL]: 
update t2 set c2=11 where c1=1

[QUERY SQL]: 
SELECT t2.* FROM t2 WHERE c1=1;

*/ 
REPLACE INTO `jingtian_test`.`t2` VALUES (1,11,1);

/* 
[SQL]: 
update tab2 set c2=11 where id=1

[ERROR MESSAGE]: 
It is not supported to generate rollback plan for tables without primary key or unique key
*/ 

包含以下几部分内容:

  • 原始的变更 SQL 语句(仅针对 UPDATE/DELETE 语句)。
  • 查询原始变更数据的 SQL 语句。
  • 生成的回滚 SQL。
  • 若针对一条 UPDATE/DELETE 变更 SQL 无法生成回滚 SQL,则其原因会显示在 [ERROR MESSAGE]中。

ODC 如何自动生成一条回滚 SQL

下面是 ODC 根据一条 SQL 生成对应的回滚 SQL 的流程图:

  • SQL 解析:通过 SQL 解析器遍历 SQL 语法树从而将一条 SQL 解析为 SQL 对象。
  • SQL 校验:基于 SQL 对象校验是符合能够生成对应的回滚 SQL 的条件,包括:
    1. 判断是否是 UPDATE/DELETE SQL,ODC 仅针对 UPDATE/DELETE 语句生成对应的回滚 SQL;
    2. 若是 OB MYSQL 模式,判断变更表是否具有主键或唯一建,对于没有主键或唯一键的表执行的变更 SQL 不支持生成回滚 SQL。
  • 基于 SQL 对象生成查询原始变更数据的 SQL。
  • 查询原始变更数据。
  • 基于 SQL 对象和原始变更数据生成对应的回滚 SQL:
    • OB MYSQL 模式针对 UPDATE 语句生成 REPLACE INTO 的回滚 SQL;
    • OB ORACLE 模式针对 UPDATE 语句生成 DELETE 语句和 INSERT INTO 语句;
    • 针对 DELETE 语句生成 INSERT INTO 语句。

接下来详解介绍每一个流程的具体实现。

SQL 解析

SQL 解析可以理解为对 SQL 进行建模,将原始 SQL 语句转化为一个 SQL 对象。我们根据 SQL 的词法和语法文件可以生成 SQL 的词法分析器和语法分析器。词法分析阶段将 SQL 语句拆解成 Token 序列,并识别出关键词、标识、常量等,而语法分析阶段基于词法分析的结果,构造出一棵抽象语法数。例如一条 SQL:

UPDATE tab1, tab2 SET tab1.c2 = 100, tab2.c2=200 WHERE tab1.c1 = tab2.c1;

生成对应的抽象语法树如下图:

通过遍历语法树将其转化为一个 SQL 对象:

可以看到,这个 SQL 对象实际上是将 SQL 语句结构化了,对 SQL 的各个部分都定义了相应的抽象,比如针对 where 的查询条件我们定义成了 CompoundExpression对象。通过将 SQL 语句解析成对象,我们就可以围绕这个对象编写生成对应回滚 SQL 的处理逻辑。

SQL 校验

SQL 校验阶段就是基于解析出来的 SQL statement 对象去做一些校验的逻辑:

  • 判断该 SQL 的类型是否是 UPDATE/DELETE 类型。
  • 针对 OB MYSQL 模式,我们需要做格外的校验变更表是否具有主键或者唯一键的逻辑判断。之所以有这个校验逻辑是由于首先后续的批量查询策略逻辑依赖主键/唯一键,其次针对 UPDATE 语句生成的回滚 SQL 是 REPLACE INTO,该语句也依赖主键/唯一键。通过 SQL 对象我们可以获取到 update 语句的 table_references 对象,我们就基于这个变更的 table 名用以下去查询校验该 table 是否具有主键或者唯一键:
-- 查询主键
SHOW INDEX FROM table_name WHERE Non_unique = 0 and Key_name='PRIMARY';

-- 查询唯一建
SHOW INDEX FROM table_name WHERE Non_unique = 0;

而针对 OB ORACLE 模式,我们直接采用 ROWID 作为每一张变更表的唯一建,因此不需要有校验变更表是否具有主键或者唯一键的逻辑。

  • 校验该变更 SQL 是否符合能够生成回滚 SQL 的语句。比如如下 SQL:
UPDATE t1, t2 set col1=2222, col2=333 WHERE t1.c1=t2.c1;

由于 table_references 中涉及多个表,但是 set column_name=... 时没有指明该column_name 的表名,导致我们仅根据这一条 SQL 无法直接确认变更的字段属于哪个表,因此该 SQL 不符合能够生成回滚 SQL 的语句。这种情况只需稍做修改,指明列所属的表就可以支持生成回滚 SQL:

UPDATE t1, t2 set t1.col1=2222, t2.col2=333 WHERE t1.c1=t2.c1; 

查询原始变更数据

如何基于一条 SQL 生成对应的查询原始数据的 SQL 呢?其实核心逻辑就是基于解析出的 SQL 对象和 SQL 语句格式去获取我们需要的信息进而拼接出查询 SQL。拿 UPDATE 语句为例,以下是 OB MYSQL 的 UPDATE 语句的格式:

UPDATE [IGNORE] table_references
    SET update_asgn_list
    [WHERE where_condition] 
    [ORDER BY order_list]
    [LIMIT row_count];

table_references:
    tbl_name [PARTITION (partition_name,...)] [, ...]

update_asgn_list:
    column_name = expr [, ...]

order_list: 
    column_name [ASC|DESC] [, column_name [ASC|DESC]...]
    

简单示例

比如基于以下 SQL:

UPDATE tab1, tab2 SET tab1.c2 = 100, tab2.c2=200 WHERE tab1.c1 = tab2.c1;

通过 SQL 解析后基于 SQL 对象我们可以获取该 SQL Statement 的 table_references、update_asgn_list 和 where_condition,通过 update_asgn_list 我们可以知道该 SQL 涉及的变更表有2个:tab1 和 tab2,进而我们就可以针对每个变更表生成的查询 SQL :

SELECT * FROM tab1 WHERE tab1.c1 = tab2.c1;

SELECT * FROM tab2 WHERE tab1.c1 = tab2.c1;

当然以上的示例 SQL 是一个最简单的例子,复杂一点的场景比如涉及 多表 join 和 子查询 的场景又该怎么生成对应的查询 SQL 呢?其实不管 SQL 多复杂我们的核心都是基于 SQL Statement 去拼接出查询 SQL。

考虑如下涉及多表 join 的 SQL:

UPDATE tab1 v1 inner join tab2 v2 inner join tab3 v3 on v1.c1 = v2.c1 and v1.c1=v3.c1 SET v1.c2=200, v2.c2=200;

针对这条 SQL 我们通过解析 table_references、 update_asgn_list 从而拼接的查询 SQL 如下:

SELECT v1.* FROM tab1 v1 inner join tab2 v2 inner join tab3 v3 on v1.c1 = v2.c1 and v1.c1=v3.c1;

SELECT v2.* FROM tab1 v1 inner join tab2 v2 inner join tab3 v3 on v1.c1 = v2.c1 and v1.c1=v3.c1;

批量查询策略

获取到基于原始 SQL 生成的查询 SQL 后,我们就可以执行查询 SQL 来获取原始数据了。在查询数据的时候可能会遇上这个问题:一次查询出的数据过大,导致内存溢出怎么办?针对这个问题传统的处理方式也有很多,比如通过 limit 分页查询,但是这种方式在我们的场景下不适用,比如如果原始 SQL 就带了 limit 那么这种方式就失效了。ODC 采用根据表的主键或唯一键(优先采用主键)拼接批量查询 SQL 的方式来解决这个问题。

OB MYSQL 模式

比如我们通过查询 SQL 可以获取到表 tab1 的主键列为 c1,如果原始的查询 SQL 如下:

SELECT tab1.* FROM tab1 WHERE c3 > 1;

我们先查询出所有变更行数据的主键值:

SELECT tab1.c1 FROM tab1 WHERE c3 > 1;

通过以上 SQL 我们就可以查询出变更的总行数以及每一行的主键值,若总变更行数为 1500 且设置的批量查询的大小为 1000,也就是每次查询最多获取 1000 行的数据,那么基于以上查询 SQL 得到的批量查询 SQL 为:

SELECT tab1.* FROM tab1 WHERE c3 > 1 AND c1 IN (1,2,3, ..., 1000);

SELECT tab1.* FROM tab1 WHERE c3 > 1 AND c1 IN (1001,1002,1003, ..., 1500);

这样以来就可以做到批量查询原始变更数据了。由于增加的 where 条件也是走索引的,因此也不存在性能瓶颈问题。

OB ORACLE 模式

针对 ORACLE 模式我们直接利用 ROWID 来拼接批量查询 SQL。比如原始 SQL;

SELECT tab1.* FROM tab1 WHERE c3 > 1;

我们先查询出所有变更行数据的 ROWID 值:

SELECT ROWID FROM tab1 WHERE c3 > 1;

那么基于以上查询 SQL 得到的批量查询 SQL 为:

SELECT tab1.* FROM tab1 WHERE c3 > 1 AND ROWID IN (...);

生成回滚 SQL

通过以上处理逻辑,我们已经获得了原始变更数据,那么接下来就是最后一步基于变更行数据生成回滚 SQL 了。

UPDATE 语句

OB MYSQL 模式

针对 OB MYSQL 模式,UPDATE 语句生成的对应回滚 SQL 为 REPLACE INTO 语句,REPLACE INTO 用于实时覆盖写入数据。写入数据时,会先根据主键或唯一键判断待写入的数据是否已经存在于表中,并根据判断结果选择不同的方式写入数据:

  • 如果待写入数据已经存在,则先删除该行数据,然后插入新的数据。
  • 如果待写入数据不存在,则直接插入新数据。

这里要求变更表必须有主键或者是唯一索引,否则 replace into 会直接插入数据(等效于 INSERT INTO),这可能会导致表中出现重复的数据。

最终 ODC 生成的完整的备份回滚 SQL 文件如下所示:

/* 
[SQL]: 
update tab set col2=2 where col=1;

[QUERY SQL]: 
SELECT tab.* FROM tab WHERE col=1;

*/ 
REPLACE INTO `schema_name`.`tab` VALUES (1,1,1);

OB ORACLE 模式

针对 OB ORACLE 模式,会先生成 DELTE 语句来删除变更数据,然后生成 INSERT INTO 语句插入原始的变更前的数据,从而避免插入数据时存在主键或者唯一键的冲突。

/* 
[SQL]: 
UPDATE TAB1 set c2=2 where c1=1

[QUERY SQL]: 
SELECT TAB1.* FROM TAB1 WHERE c1=1;

*/ 
DELETE FROM TAB1 WHERE c1=1;
INSERT INTO "TEST"."TAB1" VALUES (1,1);

DELETE 语句

针对 DELETE 语句,生成的回滚 SQL 为 INSERT INTO 语句。例如针对以下变更 SQL:

delete from tab where col=1;

最终生成的备份回滚文件内容如下:

/* 
[SQL]: 
delete from tab where col=1;

[QUERY SQL]: 
SELECT tab.* FROM tab WHERE col=1;

*/ 
INSERT INTO `schema_`.`tab` VALUES (1,1,1);

结语

感谢您的阅读~ODC 已于 2023 年 DTCC 大会上正式宣布开源。ODC 希望通过开源,与社区共同打造一款帮助 Dev 和 DBA 真正实现“ONE team”的企业级数据库协同开发工具。如果你对这个开源项目感兴趣,欢迎以任何形式参与 ODC 社区。无论是贡献代码、提出问题、分享见解,或者仅仅是表达对这个开源项目的喜爱与支持,都将成为推动 ODC 项目发展的动力。

↓ 前往 GitHub,深入了解 ODC 的更多细节

GitHub - oceanbase/odc: OceanBase Developer Center(ODC), An open-source, enterprise-grade database tool for collaborative development

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1622326.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024王鹍申论重难点:材料的概括与处理

2024王鹍申论重难点:材料的概括与处理,是备考公务员申论考试的关键一环。王鹍老师以其深厚的理论功底和丰富的实践经验,深入剖析了申论材料的特点和概括方法,同时传授了有效的材料处理技巧。通过王鹍老师的讲解,考生们…

Winseeing汇信外贸软件行业版,助力面辅料外贸公司实现降本增效

面辅料外贸出口,一直是国民经济发展中的重要组成部分。在当前全球贸易环境动荡不安的背景下,面辅料外贸出口面临着诸多挑战和机遇。亚洲是我面料出口的主要市场,据海关数据统计显示,2024年1-2月我对亚洲国家累计出口面料69.3亿美元…

leetcode多个测试用例之间相互影响导致提交失败

背景 在做一道easy题,二叉树的中序遍历,我提交的代码如下 from typing import (Optional,List )# Definition for a binary tree node. class TreeNode:def __init__(self, val0, leftNone, rightNone):self.val valself.left leftself.right right…

利用FCL实现更加精准的碰撞检测

一,需求 利用OSG结合FCL实现实现精准的碰撞检测。 二,效果 看这里 利用FCL实现更加精准的碰撞检测 – Qt hello 三,分析 我们看如下这张图,碰撞的逻辑就是,在一个三维场景中,构造一个实体,…

机器学习笔记(二)回归

一、线性回归 线性回归是一种用于预测的统计方法,特别适用于连续值预测。📈线性回归通过最小化误差的平方和来寻找一个线性关系,用于预测一个变量(因变量)基于一个或多个其他变量(自变量)的值。…

远程控制安卓手机:便捷、高效与安全的方法

在移动设备的领域里,远程控制安卓手机的能力也变得越来越重要。这种技术可以让我们在远程地点方便地操作手机,无论是处理紧急事务、帮助他人解决问题,还是仅仅为了享受科技带来的便利。本文将为你介绍2种便捷、高效且安全的方法,让…

笔试狂刷--Day6(岛屿数量+模拟)

大家好,我是LvZi,今天带来笔试狂刷--Day6 一.在字符串中找出连续最⻓的数字串 1.题目链接 在字符串中找出连续最⻓的数字串 2.题目分析 使用双指针模拟 3.代码实现 import java.util.Scanner; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {p…

Linux的学习之路:20、进程信号(2)

摘要 本章讲一下进程信号的阻塞信号和捕捉信号和可重入函数 目录 摘要 一、阻塞信号 1、阻塞信号 2、信号集操作函数 二、捕捉信号 1、内核如何实现信号的捕捉 2、代码实演 三、可重入函数 一、阻塞信号 1、阻塞信号 实际执行信号的处理动作称为信号递达(Delivery) …

文末送资料 | AI大模型接入指南:免费畅聊公众号新时代!附搭建教程

目录 今天内容有点意思! 福利:拉到最后,免费送资料,你想要的全都有 我把公号接入了,字节跳动的云雀AI大模型! 先给大家看几个案例 重点来了 如何将公号接入AI大模型呢? 1、创建AI聊天机器…

海南封关怎么看?win战略会任志雄解析

今年海南自由贸易港建设也进入了新阶段:将在2025年年底前适时启动全岛封关运作,封关后的海南将以全新姿态迎接更广泛的发展机遇。 封关在即,企业有何感受?还有哪些准备工作?封关后的海南将呈现怎样的状态?近日,红星资本局记者深入实地了解海南自贸港如何成型起势。 利好当…

快手不发作品ip地址会变吗

在数字时代,我们每个人的在线行为都留下了独特的痕迹。这些痕迹不仅仅是我们的言论或行为,还包括我们的IP地址——一个在网络世界中标识我们位置的数字标签。近年来,随着短视频平台的兴起,如快手这样的应用已经深入人们的日常生活…

sentinel-1.8.7与nacos-2.3.0实现动态规则配置、双向同步

😊 作者: 一恍过去 💖 主页: https://blog.csdn.net/zhuocailing3390 🎊 社区: Java技术栈交流 🎉 主题: sentinel-1.8.7与nacos-2.3.0实现动态规则配置、双向同步 ⏱️ 创作时…

2024年大数据应用、智能控制与软件工程国际会议(BDAICSE2024)

2024年大数据应用、智能控制与软件工程国际会议(BDAICSE2024) 会议简介 我们诚挚邀请您参加2024年大数据应用、智能控制和软件工程国际会议(BDAICSE2024)。这次会议将在美丽的长沙市举行。 本次大会旨在汇聚全球大数据应用、智能控制、软件工程等领…

常见大厂面试题(SQL)02

小鹏面试题: 小鹏汽车充电每辆车连续快充最大次数 原表charging_data idcharge_timecharge_typeXP10012023/11/20 8:45快充XP10012023/11/21 20:45快充XP10012023/11/22 8:45快充XP10012023/11/23 8:45慢充XP10012023/11/25 8:45快充XP10022023/11/25 8:45快充XP10022023/11/…

kubernetes中Pod资源的使用限制

一、概述 当kubernetes调度创建Pod后,Pod是否有足够的资源来运行容器,是非常重要的。资源分为两种类型——容器请求的资源和容器被限制的资源。 请求和限制是kubernetes控制集群cpu和内存等资源的重要方式,他们是两种不同的机制 容器请求的资…

C语言之回调函数+可变参数__VA_ARGS__:用法实例(四十八)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

GaussDB数据库SQL系列-聚合函数

背景 在这篇文章中,我们将深入探讨GaussDB数据库中聚合函数的使用和优化。聚合函数是数据库查询中非常重要的工具,它们可以对一组值执行计算并返回单个值。例如,聚合函数可以用来计算平均值、总和、最大值和最小值。 这些功能在数据分析和报…

C语言 | Leetcode C语言题解之第48题旋转图像

题目&#xff1a; 题解&#xff1a; void swap(int* a, int* b) {int t *a;*a *b, *b t; }void rotate(int** matrix, int matrixSize, int* matrixColSize) {// 水平翻转for (int i 0; i < matrixSize / 2; i) {for (int j 0; j < matrixSize; j) {swap(&matr…

Linux_网络基础2_3

文章目录 一、应用层协议1.我写的socket是在干什么&#xff1f;2.再谈"协议"1.问题1 # 2.问题23.造轮子——定制应用协议4.使用json来完成应用协议1.安装库2.使用 —— 序列化3.使用 —— 反序列化 二、HTTP协议1.认识URL2.http协议的请求格式和响应格式3.编写响应 -…

大模型(e.g., ChatGPT)里面的一些技术和发展方向

文章目录 如何炼成ChatGPT如何调教ChatGPT如何武装ChatGPT一些大模型的其他方向prompt tuningInstruction tuning 这个是基于视频 https://www.bilibili.com/video/BV17t4218761&#xff0c;可以了解一下大模型里面的一些技术和最近的发展&#xff0c;基本都是2022你那以来的发…