OceanBase 中的ROWID与Oracle的差异与如何迁移

1. ROWID

1.1 OB和Oracle中rowid的区别

正如大家所知道的,OceanBase兼容Oracle的rowid特性,但在其生成规则上却存在不同,具体表现如下:

OceanBase

● 定义:OceanBase(简称 OB)的rowid是通过主键(包括隐藏主键)直接经过base64编码计算得出的,因此一旦主键发生变动,相应的rowid也会随之改变。关于主键的生成规则,具体如下:

○有主键非分区表,用户定义的主键

○有主键分区表,用户定义的主键

○无主键非分区表,内部生成sequence作为隐藏主键

○无主键分区表,分区键+sequence作为隐藏主键

●长度:17个字符。

Oracle

●定义:该值表明了该行在oracle数据库中的物理具体位置。保存rowid需要10个字节或者是80个位二进制位。这80个二进制位分别是:

○1. 数据对象编号,表明此行所属的数据库对象的编号,每个数据对象在数据库建立的时候都被唯一分配一个编号,并且此编号唯一。数据对象编号占用大约32位。

○2. 对应文件编号,表明该行所在文件的编号,表空间的每一个文件标号都是唯一的。文件编号所占用的位置是10位。

○3. 块编号,表明改行所在文件的块的位置块编号需要22位。

○4. 行编号,表明该行在行目录中的具体位置行编号需要16位。

●长度:rowid需要 10个字节的存储空间,并用18个字符来显示。

1.2 用户业务场景和迁移方案

业务场景

●表A:存储业务单据信息,数据量较大;

●表B:A表关联表,表中有一列存放B表的rowid值;

●业务场景需要经常通过B表去A表关联取数,为了优化取数性能直接通过rowid关联。

迁移方案

由于迁移后OB rowid长度和Oracle不一致,且定义完全不同,列数据迁移过去会失去原有意义成为垃圾数据。具体改造方案如下:

1.表结构调整:删除rowid类型列,数据也不做迁移;

2.性能调优:创建合适索引,通过其他字段关联查询。由于业务侧预留了业务主键可以关联,实测性能满足客户需求。

1.3 Oracle rowid发生变化的场景

由于OMS迁移过程中全量和增量迁移都和源端oracle的rowid密切关联(无论有主键表还是无主键表),所以我们需要密切关注Oracle源端的rowid变化场景,迁移过程中都要避免。Oracle rowid发生变化的场景如下:

○1. Oracle 行迁移

○2. 另外一些不急于rowmovement会导致rowid修改的动作,比如move和逻辑导出再导入

Oracle 行迁移(row movement)场景

●行迁移 ( Row movement): 默认情况下,oracle数据块中的一行其生命周期内是不会发生移动的,即块的rowid不会发生改变。但是在某些情景下,我们希望行的rowid可以发生变化,这时候我们就需要启动表的row movement特性。

复制代码
-- 启用row movement特性
Alter table table_name enable row movement;
(1)分区表

当我们允许分区表的分区键是可更新的时候,如果分区键的更新导致当前修改的数据条目需要移动到其他分区,此时就会发生rowid的改变。

复制代码
create table test_rowid(id number,test_value varchar2(10))
partition by list(test_value)(
partition p1 values('1'),
partition p2 values('2'),
partition p3 values('3'));

insert into test_rowid values(1,'1');
insert into test_rowid values(2,'2');
insert into test_rowid values(3,'3');
insert into test_rowid values(4,'1');
commit;

select rowid,id,test_value from test_rowid ;
/*ROWID	ID	TEST_VALUE
AAAefAAAHAADJMWAAA	1	1
AAAefAAAHAADJMWAAB	4	1
AAAefBAAHAADJcWAAA	2	2
AAAefCAAHAADJsWAAA	3	3 */
 
update test_rowid set test_value=2 where id=4;
-- ORA-14402: updating partition key column would cause a partition change
 
alter table test_rowid enable row movement;
 
update test_rowid set test_value=2 where id=4;
-- 1 row updated.

select rowid,id,test_value from test_rowid ;
/*ROWID	ID	TEST_VALUE
AAAefAAAHAADJMWAAA	1	1
AAAefBAAHAADJcWAAA	2	2
AAAefBAAHAADJcWAAB	4	2
AAAefCAAHAADJsWAAA	3	3 */
id=4的列rowid发生变化。
(2)闪回操作

在闪回操作时,我们同样需要开启表的row movement特性。

复制代码
alter table test_rowid disable row movement;
-- Table altered.
 
SQL> select current_scn from v$database;
-- 38719199
 
select rowid,id,test_value from test_rowid where test_value=1;
/* ROWID	ID	TEST_VALUE
AAAefAAAHAADJMWAAA	1	1 */ 

delete from test_rowid where test_value=1;
commit;
 
flashback table test_rowid to scn 38719199;
-- ORA-08189: cannot flashback the table because row movement is not enabled

alter table test_rowid enable row movement;
-- Table altered.
 
flashback table test_rowid to scn 38719199;
-- Flashback complete.
 
select rowid,id,test_value from test_rowid where test_value=1;
/* ROWID	ID	TEST_VALUE
AAAefAAAHAADJMWAAC	1	1 */

flashback table原理:oracle flashback table 是通过临时表来实现的。

复制代码
create table hh(id number);
insert into hh values(1);
commit;
 
alter table hh enable row movement;
select current_scn from v$database;
--  1635103

update hh set id = 2;
commit; 
 
alter session set tracefile_identifier = 'ee';
alter session set sql_trace=true;
flashback table hh to scn 1635103;
-- Flashback complete.
 

通过查看trace文件,我们可以发现oracle  flashback table 是通过一个临时表sys_temp_fbt来实现的。
trace文件中的部分内容如下:
********************************************************************************
sqlid='dtjmzuugu6ktw'
INSERT /*+ APPEND */ into SYS_TEMP_FBT SELECT /*+ FBTSCAN FULL(S) PARALLEL(S, DEFAULT) */ :1, :2, :3, rowid, SYS_FBT_INSDEL FROM "APPTEST"."HH" as of SCN :4 S
********************************************************************************
sqlid='bytpvbcb8zbb6'
/* Flashback Table */ DELETE /*+ BYPASS_UJVC */ FROM (SELECT /*+ ORDERED USE_NL(S) PARALLEL(S,DEFAULT) PARALLEL(T,DEFAULT) */ S.rowid FROM SYS_TEMP_FBT T, "APPTEST"."HH" S WHERE T.rid = S.rowid and T.action = 'D' and T.object#  = : 1) V
********************************************************************************
sqlid='a3h5cbfc5b6xv'
/* Flashback Table */ INSERT /*+ PARALLEL(S, DEFAULT) PARALLEL(T, DEFAULT) */ INTO "APPTEST"."HH" SELECT /*+ USE_NL(S) ORDERED PARALLEL(S, DEFAULT) PARALLEL(T, DEFAULT) */ S.* FROM SYS_TEMP_FBT T , "APPTEST"."HH" as of SCN :1 S WHERE T.rid = S.rowid and T.action = 'I' and T.object# = :2 
 
由此可见,oracle是通过SYS_TEMP_FBT进行删除操作,而后进行插入操作,
因此行的rowid有可能发生改变。
 SQL> select * from sys_temp_fbt ;
SCHEMA     OBJECT_NAME             OBJECT# RID                            A
---------- -------------------- ---------- ------------------------------ -
hh       hh                      76906 AAASxqAAGAAAAC0AAA             D
hh       hh                      76906 AAASxqAAGAAAAC0AAA             I


SQL> select tname,tabtype from tab;
TNAME                    TABTYPE
------------------------------ -------
HH                     TABLE
SYS_TEMP_FBT       TABLE

drop表Oracle有另外的回收站技术恢复,不需要开ROW MOVEMENT

复制代码
SQL> ALTER TABLE test_rowid DISABLE ROW MOVEMENT;  
Table altered.  
SQL> DROP TABLE test_rowid;  
Table dropped.  
SQL> FLASHBACK TABLE test_rowid TO BEFORE DROP;  
Flashback complete.  
没错,因为drop表Oracle有另外的回收站技术恢复过来,而删除几行记录是不能 直接通过回收站恢复的。
(3)回收空间

在收缩空间时,也会造成行的移动

复制代码
SQL> alter table hh disable row movement;
Table altered.
 
SQL> alter table hh shrink space;
alter table hh shrink space
*
ERROR at line 1:
ORA-10636: ROW MOVEMENT is not enabled
 
SQL> alter table hh enable row movement;
Table altered.
 
SQL> alter table hh shrink space;
Table altered.
 
Shrink space操作(without  compact)也会导致所有已经打开的游标失效,因此需要谨慎使用!

1.4 OB rowid变化场景:

对于源端是OB的情况,OMS迁移并不会依赖rowid,通过前面的介绍也可以看到OB rowid的变化是很频繁的,主要变化场景如下:

●有主键非分区表,主键发生变化,rowid变化

●有主键分区表,因为分区键包含在主键内,所以同上

●无主键非分区表,对于一行记录rowid不会变化。

●无主键分区表,分区键发生变化时,rowid变化

相关推荐
傻啦嘿哟12 分钟前
Python 数据分析与可视化实战:从数据清洗到图表呈现
大数据·数据库·人工智能
cookqq39 分钟前
mongodb源码分析session异步接受asyncSourceMessage()客户端流变Message对象
数据库·sql·mongodb·nosql
呼拉拉呼拉1 小时前
Redis故障转移
数据库·redis·缓存·高可用架构
什么都想学的阿超1 小时前
【Redis系列 04】Redis高可用架构实战:主从复制与哨兵模式从零到生产
数据库·redis·架构
pp-周子晗(努力赶上课程进度版)1 小时前
【MySQL】视图、用户管理、MySQL使用C\C++连接
数据库·mysql
斯特凡今天也很帅1 小时前
clickhouse常用语句汇总——持续更新中
数据库·sql·clickhouse
超级小忍3 小时前
如何配置 MySQL 允许远程连接
数据库·mysql·adb
吹牛不交税3 小时前
sqlsugar WhereIF条件的大于等于和等于查出来的坑
数据库·mysql
hshpy3 小时前
setting up Activiti BPMN Workflow Engine with Spring Boot
数据库·spring boot·后端
文牧之4 小时前
Oracle 审计参数:AUDIT_TRAIL 和 AUDIT_SYS_OPERATIONS
运维·数据库·oracle