Oracle与GreatSQL差异:更改唯一索引列

news/2025/1/13 15:57:19/文章来源:https://www.cnblogs.com/greatsql/p/18519779

Oracle与GreatSQL差异:更改唯一索引列

1.问题来源

在从Oracle迁移到GreatSQL的应用系统中,一条普通的update语句在GreatSQL中却报错,需要进行SQL语句的改写。把实际问题简化为下面简单情况进行说明。

在Oracle下,可以正常执行的update语句。

-- 建表
CREATE TABLE test.test1 (id INT PRIMARY KEY,k INT NOT NULL,c CHAR(120) NOT NULL,pad CHAR(60) NOT NULL
);-- 创建唯一索引
CREATE UNIQUE INDEX ui_test1_k ON test.test1 (k);-- 插入数据
INSERT INTO test.test1 VALUES 
(1, 1, 'cc', 'pad'),
(2, 2, 'cc', 'pad'),
(3, 3, 'cc', 'pad'),
(4, 4, 'cc', 'pad');-- 执行 UPDATE 语句
UPDATE test.test1 SET k = k + 1;
UPDATE test.test1 SET k = k - 1;

在GreatSQL下准备测试表和数据:

CREATE TABLE `test1` (`id` int NOT NULL AUTO_INCREMENT,`k` int NOT NULL DEFAULT '0',`c` char(120) COLLATE utf8mb4_bin NOT NULL DEFAULT '',`pad` char(60) COLLATE utf8mb4_bin NOT NULL DEFAULT '',PRIMARY KEY (`id`),UNIQUE KEY `ui_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;greatsql> INSERT INTO test1 VALUES (1, 1, 'cc', 'pad');
greatsql> INSERT INTO test1 VALUES (2, 2, 'cc', 'pad');
greatsql> INSERT INTO test1 VALUES (3, 3, 'cc', 'pad');
greatsql> INSERT INTO test1 VALUES (4, 4, 'cc', 'pad');

同样的update语句,在GreatSQL下执行报错:

greatsql> UPDATE test1 SET k = k + 1;
ERROR 1062 (23000): Duplicate entry '2' for key 'test1.ui_k'

在GreatSQL下,UPDATE语句为什么报错呢?使用什么方法可以高效执行呢?

2.解决方法

由UPDATE语句的报错可知是唯一键重复的问题,将k=1的行更改k=k+1=2,与k=2的行重复。解决方法有2个方向:

  • 让唯一索引暂时失效,update完成后再启用
  • 让数据按一定的顺序执行,避免数据重复

尝试设置 unique_checks为0

设置会话系统变量unique_checks=0,则允许存储引擎假定输入数据中不存在重复的键。如果您确定您的数据不包含唯一性冲突,那么您可以将它设置为0,以加快将大型表导入InnoDB的速度。将此变量设置为0并不要求存储引擎忽略重复的键。仍然允许引擎检查它们,并且如果它检测到它们,就发出重复索引的错误。

实际测试,设置UNIQUE_CHECKS=0,update语句仍然报错。

greatsql> SET UNIQUE_CHECKS=0;
Query OK, 0 rows affected (0.00 sec)greatsql> UPDATE test1 SET k = k + 1;
ERROR 1062 (23000): Duplicate entry '2' for key 'test1.ui_k'

方法1:删除唯一索引,update后重建

删除唯一索引,update后重建唯一索引的方法,有2个DDL操作,由于DDL前会自动提交事务,这种处理方法不能和其他操作在同一个事务中,同时也存在update后(有重复值)无法创建唯一索引的风险。适合数据的手工一次性处理。

greatsql> ALTER TABLE test1 DROP index kc;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0greatsql> UPDATE test1 SET k=k+1 ;
Query OK, 100 rows affected (0.01 sec)
Rows matched: 100  Changed: 100  Warnings: 0greatesql> ALTER TABLE test1 ADD UNIQUE key ui_k(k);
Query OK, 0 rows affected (0.09 sec)
Records: 0  Duplicates: 0  Warnings: 0

方法2:update按顺序执行

可以在update语句中使用order by子句,按照k值顺序执行,避免update后的数据与原有数据重复。

#k=k+1时,需要按照降序执行
greatsql> UPDATE test1 SET k=k+1 ORDER BY k DESC; 
Query OK, 4 rows affected (0.01 sec)
Rows matched: 4  Changed: 4  Warnings: 0greatsql> UPDATE test1 SET k=k+1 ORDER BY k ; 
ERROR 1062 (23000): Duplicate entry '2' for key 'test1.ui_k'#k=k-1时,需要按照升序执行
greatsql> UPDATE test1 SET=k-1 ORDER BY k ;
Query OK, 4 rows affected (0.01 sec)
Rows matched: 4  Changed: 4  Warnings: 0greatsql> UPDATE test1 SET k=k-1 ORDER BY k DESC; 
ERROR 1062 (23000): Duplicate entry '4' for key 'test1.ui_k'

执行效率对比

对比方法1和方法2的执行效率。

#方法1:删除唯一索引,UPDATE后重建
greatsql> ALTER TABLE test1 DROP index k;
Query OK, 0 rows affected (0.17 sec)
Records: 0  Duplicates: 0  Warnings: 0greatsql> UPDATE test1 SET k=K+1;
Query OK, 1000000 rows affected (35.08 sec)
Rows matched: 1000000  Changed: 1000000  Warnings: 0greatsql> ALTER TABLE test1 ADD UNIQUE index kc(k,c);
Query OK, 0 rows affected (12.35 sec)
Records: 0  Duplicates: 0  Warnings: 0#方法2:UPDATE按顺序执行
greatsql> UPDATE test1 set k=K+1 ORDER BY k DESC;
Query OK, 1000000 rows affected (1 min 36.81 sec)
Rows matched: 1000000  Changed: 1000000  Warnings: 0

总结:执行时间 方法1:方法2=47.50 : 96.81 = 1 : 2.04 ,方法1(删除唯一索引,update后重建)比方法2(update按顺序执行)执行行效率高1倍。

3.GreatSQL源码分析

通过对GreatSQL源码的分析,了解到上面update语句从server层调用InnoDB存储引擎层函数的调用关系如下,每update 1行数据调用ha_update_row()一次,每update 1行数据后都要检查唯一索引是否发生冲突。

#server层
Sql_cmd_update::update_single_table()
->ha_update_row() //更新一行数据                                                                             #innodb 存储引擎层-> ha_innobase::update_row() //更新innodb一行数据-> row_update_for_GreatSQL() //修改或删除数据-> row_update_for_GreatSQL_using_upd_graph() //更新行->row_upd_step()  //更新行    ->row_upd()  //更新索引->row_upd_sec_step()  //更新索引->row_ins_sec_index_entry()  //向索引中插入记录->row_ins_sec_index_entry_low()  //向索引中插入记录->row_ins_scan_sec_index_for_duplicate()  //检查索引重复值->row_ins_dupl_error_with_rec() //检查唯一索引冲突
  1. handler::ha_update_row 函数的主要功能是更新表中的一行数据,并记录该操作到二进制日志中。
  2. ha_innobase::update_row函数的主要功能是更新InnoDB表中的一行数据。
  3. row_update_for_GreatSQL 修改或删除数据行。
  4. row_update_for_GreatSQL_using_upd_graph 函数的主要功能是处理 GreatSQL 的行更新操作。
  5. row_upd_step 函数的主要功能是处理行更新操作。
  6. row_upd函数是更改数据行影响的索引。
  7. row_upd_sec_step函数是根据记录行的更改或删除,更改二级索引或删除二级索引。
  8. row_ins_sec_index_entry 函数的主要功能是向二级索引中插入一条记录。
  9. row_ins_sec_index_entry_low 函数的主要功能是向二级索引中插入一个索引项。它首先进行一些初始化和检查,然后根据索引类型(空间索引或普通索引)进行搜索。在搜索过程中,它会检查唯一性约束,并根据需要执行插入或修改操作。
  10. row_ins_scan_sec_index_for_duplicate函数的主要功能是扫描非聚集唯一索引,以检查是否存在与要插入的索引条目重复的记录。
  11. row_ins_dupl_error_with_rec 函数的主要功能是检查在插入索引条目时是否会发生唯一键冲突。它通过比较要插入的条目和现有记录的字段来确定是否存在重复。

4.总结

在更改唯一索引列时,Oracle是完成SQL语句全部数据的更改后,再检查唯一索引的冲突;GreatSQL则是在SQL语句更改每1条数据后,在更新索引数据检查唯一索引的冲突。在应用系统从Oracle迁移到GreatSQL时,需注意予以改写。

5.延伸阅读

  • UPDATE 时主键冲突引发的思考(https://imysql.com/2008_06_17_sth_about_update_duplicate_key)

Enjoy GreatSQL 😃

关于 GreatSQL

GreatSQL是适用于金融级应用的国内自主开源数据库,具备高性能、高可靠、高易用性、高安全等多个核心特性,可以作为MySQL或Percona Server的可选替换,用于线上生产环境,且完全免费并兼容MySQL或Percona Server。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

社区博客有奖征稿详情:https://greatsql.cn/thread-100-1-1.html

image-20230105161905827

技术交流群:

微信:扫码添加GreatSQL社区助手微信好友,发送验证信息加群

image-20221030163217640

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PVE7.1虚拟机安装黑群晖教程

本教程基于Proxmox VE(PVE)7.1虚拟机环境下安装群晖,兼容这块简单说明:Intel酷睿四代以下或者志强处理器建议安装Ds3615-3617-3266等版本,四代以上可以安装918-920等版本,如果你啥都不知道,安装Ds3615就对了。安装步骤1.先删除删除local-lvm分区,    具体教程PVE虚拟…

项目经理如何进行项目绩效评估

项目经理进行项目绩效评估是通过设定标准、跟踪进度、分析结果和整改措施等步骤完成的。在这个过程中,项目经理需要对各个关键绩效指标(KPIs)进行监控和评价,这样可以确保项目符合既定目标和标准。设定标准是项目绩效评估的基础,它为项目的成功定义了清晰的轨迹。 设定标准…

SMART Utility中文激活安装包 SMART Utility MacOS硬盘检测下载地址

SMART Utility是一款专为Mac OS X设计的硬盘健康状态检测工具。它利用先进的自我监测、分析与报告技术(SMART),实时监测硬盘的温度、转速、错误率等关键参数,全面评估硬盘健康状况。该软件能及时发现并预警硬盘中的潜在问题,如坏道、机械故障等,并提供详细的报告功能,帮…

JuiceFS CSI:Mount Pod 的平滑升级及其实现原理

当集群中需要升级 Mount Pod 时,目前推荐的方式是更新配置后重新挂载应用 Pod 进行滚动升级,但这种升级方式的问题在于需要业务重启。 如果对业务的使用模式很清楚时,比如没有数据写入等,也可以选择手动重建 Mount Pod 的方式。在更新配置后,手动删除已有的 Mount Pod,并…

博客搭建之路:hexo博客显示阅读时间和字数

hexo博客显示阅读时间和字数 hexo版本5.0.2 npm版本6.14.7 next版本7.8.hexo博客显示阅读时间和字数hexo版本5.0.2 npm版本6.14.7 next版本7.8.0效果如下在博客目录下安装npm install hexo-symbols-count-time --save 在_config.yml中加入配置 symbols_count_time:#文章内是否…

【鸿蒙新闻】10月29日警用鸿蒙开发者大会在北京胜利召开,开启智慧应用新时代!

10月29日,在公安部科技信息化局、公安部装备财务局指导下,由公安部第一研究所主办,鼎桥通信技术有限公司、OpenHarmony生态委员会及公共安全专委会协办的警用鸿蒙开发者大会在北京胜利召开。10月29日,在公安部科技信息化局、公安部装备财务局指导下,由公安部第一研究所主办…

如何进行能源效率优化?

优化能源效率需要遵循以下步骤:1.识别并分析能源消费者;2.设定优化目标;3.选择适当的优化策略;4.实施技术改进措施;5.持续监控和反馈。进行能源效率优化的起点是明确能源使用的主要领域。1. 识别并分析能源消费者 进行能源效率优化的第一步是了解能源的主要消费者。这包括…

laravel11:中间件传递参数

一,官方的文档: 参考地址: https://docs.golaravel.com/docs/middleware二,演示: 功能:一个中间件负责验证用户是否已登录, 传递参数的作用是:在已登录基础是否验证真人身份核验,值为1时要核验,其他情况可以不用 1, 为中间件注册一个别名: bootstrap/app.php->…

css渐变背景的顶级用法:linear-gradient()

background-image:linear-gradient(110deg, rgb(1, 228, 161) 49%, rgb(0, 0, 0) 2% 51%, rgb(226, 237, 251) 49%);linear-gradient详解: 简单实例:从头部开始的线性渐变,从红色开始,转为黄色,再到蓝色: background-image: linear-gradient(red, yellow, blue); linear-g…

冒险岛V0.79版本单机安装教程_无需虚拟机

为了学习和研究软件内含的设计思想和原理,本人花心血和汗水带来了搭建教程!!! 教程不适于服架设,严禁服架设!!!请牢记!!! 教程仅限学习使用,禁止商用,一切后果与本人无关,此声明具有法律效应!!!! 教程是本人亲自搭建成功的,绝对是完整可运行的,踩过的坑都给…

基于微服务SDK框架与JavaAgent技术,低成本助力应用高效发布

对于企业用户和开发者来说,如何尽可能以较低的成本、较好的效率来解决微服务治理过程中的各个问题是永恒的目标。本文分享自《华为云DTSE》第五期开源专刊,作者:聂子雄 华为云高级工程师、李来 华为云高级工程师。 微服务是一种用于构建应用的架构方案,可使应用的各个部分既…