首页 > 数据库 >Oracle与GreatSQL差异:更改唯一索引列

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

时间:2024-11-01 11:08:33浏览次数:1  
标签:test1 GreatSQL update 索引 Oracle greatsql row

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: 0

greatsql> UPDATE test1 SET k=k+1 ;
Query OK, 100 rows affected (0.01 sec)
Rows matched: 100  Changed: 100  Warnings: 0

greatesql> 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: 0

greatsql> 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: 0

greatsql> 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: 0

greatsql> UPDATE test1 SET k=K+1;
Query OK, 1000000 rows affected (35.08 sec)
Rows matched: 1000000  Changed: 1000000  Warnings: 0

greatsql> 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.延伸阅读


Enjoy GreatSQL

标签:test1,GreatSQL,update,索引,Oracle,greatsql,row
From: https://www.cnblogs.com/greatsql/p/18519779

相关文章

  • 【elkb】索引生命周期管理
    索引生命周期管理Indexlifecyclemanagement(索引生命周期管理)是elasticsearch提供的一种用于自动管理索引的生命周期的功能。允许使用者定义索引的各个阶段,从创建至删除。并允许使用者在每个阶段定义索引需要执行的特定动作。这些动作包含索引创建,rollover滚动规则,shrink......
  • 如何修改网站的 SEO,优化网站搜索引擎排名的方法
    关键词研究:使用工具(如GoogleKeywordPlanner)进行关键词研究,找出与你的业务相关的高流量关键词。优化标题和描述:确保每个页面的 <title> 标签和 <metadescription> 标签都包含主要关键词,并且具有吸引力。高质量内容:定期发布高质量、有价值的内容,吸引用户和搜索引擎的注意......
  • Oracle 第14章:并发控制
    在Oracle数据库中,并发控制是一个关键概念,因为它确保了多个用户或事务可以同时访问数据库而不干扰彼此的工作。并发问题主要出现在多用户环境中,当多个事务试图同时修改相同的数据时可能发生数据不一致的问题。并发问题及解决方案并发问题:脏读(DirtyReads):一个事务读取了另......
  • ObservableCollection<T>获取索引
    如果是普通类型我们直接可以用indexOf()获取,比如:ObservableCollection<string>oc=newObservableCollection<string>();oc.Add("Item1");oc.Add("Item2");oc.Add("Item3");stringitem="Item2";intindex=oc.IndexOf(ite......
  • MySQL索引
    索引概述介绍索引(index)是帮助MySQL高效获取数据的数据结构(且有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。优缺点索引结构MySQL的索引是在存储引......
  • GIS空间索引技术
    地理信息系统(GeographyInformationSystem,简称GIS)的主要任务之一是有效地检索空间数据及快速响应不同用户的在线查询。地理空间索引技术和方法是GIS的关键技术。是快速高效查询、检索和显示地理空间数据的重要指标。常用的空间索引技术介绍和比较: 网格空间索引、四叉树空间索......
  • Oracle数据库AWR报告中高等待事件优化方法
    一、理解等待事件什么是等待事件在Oracle数据库中,等待事件是指会话在执行SQL语句时,由于某些资源(如磁盘I/O、锁、缓冲区等)暂时不可用而必须等待的情况。AWR报告中的等待事件部分可以帮助我们识别数据库性能瓶颈的关键所在。确定高等待事件类型常见的高等待事件包括:......
  • MYSQL索引相关
    原sqlSELECTid,user_id,package_id,term_id,source,type,order_id,code_record_id,created_at,updated_at,version,is_deletedASdeletedFROMtbl_purchased_packageWHERE(ter......
  • Oracle、MySQL、ClickHouse的通用AES256加解密如何实现?
     Oracle、MySQL、ClickHouse的通用AES256加解密如何实现? 前段时间研究了加密算法aes,写了个文档,分享到博客上来。防。1  说明应XXX安全生产需求,对目标库目标表业务字段敏感信息进行加密密文存放,查询时通过解密得到明文进行数据使用,要求使用AES256。目前公司所使用主要......
  • 10.30 索引,外键
    索引一、索引的介绍1、什么是索引?(1)定义:索引是一种数据结构一个索引在存储的表中的数据结构;(2)索引是在表的字段上创建的(3)索引包含了一列值,这个值保存在一个数据结构中2、索引作用?(1)保证数据记录的唯一性(2)实现表与表之间的参照性(3)减少排序和分组的时间(例如在使用orderby,gr......