Oracle索引组织表与大对象平滑迁移至OceanBase的实施方案

**作者简介:**严军(花名吉远),十年以上专注于数据库存储领域,精通Oracle、Mysql、OceanBase,对大数据、分布式、高并发、高性能、高可用有丰富的经验。主导过蚂蚁集团核心系统数据库升级,数据库LDC单元化多活项目,常年负责蚂蚁重大数据库活动(如双11、双12、春节红包大促),现任阿里云数据库架构师和云计算专家,专注于金融行业数据库架构设计和咨询工作。

因最近笔者在协助金融客户完成系统的平滑迁移与升级工作。随着迁移系统数量的不断增加,发现客户对Oracle的使用的复杂度和深度都相当高。因此,本文列举了Oracle的索引组织表、大对象的特性,以及迁移到OceanBase(简称OB)的相应方案,以供参考。希望能对大家有所帮助。

1、索引组织表(Index-Organized Table, IOT)

1.1 索引组织表介绍

索引组织表是一类特殊的表,它将索引和表的数据存储在一起(或者说实际上将所有数据都放入了索引中)。普通表的数据以无序(Heap)的方式存放在数据库中。而索引组织表按照主键进行排序,以二叉树的形式对表的数据进行存储。

●索引组织表不存储ROWID,它通过主键来访问数据。

●索引组织表适合通过主键对数据进行访问的应用。

优点

1.快速的随机访问。索引和表的数据存储在一起,如果对表进行更新,Oracle只更新索引结构。

2.快速的范围扫描。索引组织表已经按照主键对数据进行排序,因此,范围扫描的速度是很快的。

3.更少的存储需求。索引数据和表的数据存储在一起,可以减少存储需求。普通的索引条目只包含索引值和指向数据行的ROWID

组成

1.索引部分。存放主键值,频繁访问的部分非主键值,指向溢出区的ROWID

2.溢出部分。用于存放非主键值。溢出区存放在一个溢出表空间中。用户可以指定溢出表空间。

1.2 问题业务场景

客户反馈OMS迁移时部分SYS_IOT开头的表迁移出现报错,原来以为是系统表,但核对时发现通过 user_objects查询能查到这个表。

最后确定这类表其实都是索引组织表的子表,且子表不支持任何操作。复现脚本如下:

-- 创建IOT时,必须要设定主键,否则报错。
CREATE TABLE TEST_IOT
(id NUMBER PRIMARY KEY,
C1 VARCHAR2(50),
C2 VARCHAR2(10))
ORGANIZATION INDEX PCTTHRESHOLD  10 OVERFLOW;

select object_name,object_type from user_objects where object_name like '%IOT%';
/* 
SYS_IOT_OVER_96983	TABLE
SYS_IOT_TOP_96983	INDEX
TEST_IOT	TABLE 
*/

-- 只需要对父表进行赋权和获取DDL操作,子表不支持任何操作。
grant select on SYS_IOT_OVER_96983 to scott;
-- ORA-25191: cannot reference overflow table of an index-organized table
select dbms_metadata.get_ddl('TABLE','SYS_IOT_OVER_96983','APPTEST') from dual;
/* ORA-31603: object "SYS_IOT_OVER_96983" of type TABLE not found in schema "APPTEST"
ORA-06512: at "SYS.DBMS_METADATA", line 6478
ORA-06512: at "SYS.DBMS_SYS_ERROR", line 105
ORA-06512: at "SYS.DBMS_METADATA", line 6465
ORA-06512: at "SYS.DBMS_METADATA", line 9202
ORA-06512: at line 1
*/


--  查询父子表对应关系
select TABLE_NAME,IOT_NAME from dba_tables where owner='APPTEST';
TEST_IOT	
SYS_IOT_OVER_96983	TEST_IOT

1.3 迁移方案

●表结构迁移:通过dbcat进行结构迁移,索引组织表会被转换成普通表(后续OMS会支持);

●数据迁移:由于Logminer捕获不到增量日志,这类表只能离线迁移。离线迁移方案建议:

○主键单字段场景:OMS效率尚可,也可以使用dataX或者导出CSV文件后导入OB的方式;

○主键多字段场景:不建议使用OMS,建议datax或者导出方式。

2. 大对象(LOB类型)

2.1 大对象介绍

Oracle

Oracle包含4种大对象类型BLOB、CLOB、NCLOB、BFILE,存储长度都为4G。具体如下:

●CLOB:内部字符大对象,存储单字节和多字节字符数据。支持固定宽度和可变宽度的字符集,常用于大文本的存储。

●NCLOB:国家语言字符集大对象,存储UNICODE类型的数据,支持固定宽度和可变宽度的字符集。

●BLOB:内部二进制大对象,存储非结构化的二进制数据大对象,它可以被认为是没有字符集语义的比特流,一般是图像、声音、视频等文件。

●BFILE:外部二进制文件,存储在数据库外的系统文件,只读的,数据库会将该文件当二进制文件处理。

OB

LOB 全称为大对象数据类型(Large Object),包括 BLOB 和 CLOB,用来存储大型和非结构化数据,例如文本、图像、视频和空间数据等。本文主要提供 OceanBase 数据库当前版本所支持的大对象数据类型的概览和使用限制。

大对象数据类型概览

OceanBase 数据库当前版本所支持的大对象数据类型的信息如下表所示。

|------|----|------------|-----------|
| 类型 | 长度 | 定义长度上限(字符) | 字符集 |
| BLOB | 变长 | 48 MB | BINARY |
| CLOB | 变长 | 48 MB | 与租户的字符集一致 |

说明:与 Oracle 通过 LOB Locator 引用数据不同,在 OceanBase 数据库中,LOB Locator 与数据保存在同一结构中。

2.2 迁移方案

●BLOB/CLOB:确定在OB支持的最大长度范围内,平迁。超出最大范围需要业务改造;

●NCLOB:OB不支持 nclob,OMS在迁移中会将字段类型转成 nvarchar2 。注意nvarchar2 上限为 32767 个字节;

●BFILE:建议在Oracle中使用代码转成BLOB后迁移,案例如下:

-- BFile实际上是Oracle数据库指向操作系统文件的一个指针。
-- 读取操作系统文件并转为BLOB代码:

-- 创建测试文件
touch /home/oracle/test.jpg
-- 创建directory对象
create directory obtest as '/home/oracle/xxx';
grant read on directory obtest to <username>;
create table obfiletest(col1 bfile,cole2 blob);
INSERT INTO obfiletest(col1) VALUES (BFILENAME ('obtest', 'test.jpg'));

-- BFILE转BLOB
Declare
  v_bfile Bfile;
  v_blob  Blob;
  v_dest  Number := 1;
  v_lang  Number := 1;
Begin
  v_bfile := bfilename('OBTEST', 'test.jpg');
  --dbms_output.put_line(v_bfile);
  dbms_lob.createtemporary(v_blob, True);
  dbms_lob.fileopen(v_bfile, dbms_lob.file_readonly);
  dbms_output.put_line(dbms_lob.getlength(v_bfile));
  dbms_lob.loadblobfromfile(dest_lob => v_blob, src_bfile => v_bfile,
                            amount => dbms_lob.getlength(v_bfile),
                            dest_offset => v_dest, src_offset => v_lang);
  Update obfiletest Set cole2 = v_blob;
  dbms_lob.fileclose(file_loc => v_bfile);
End;
/

2.3 关于CLOB字段的UNIQUE INDEX

●在创建CLOB字段的同时,Oracle会自动创建一个UNIQUE INDEX;OB支持CLOB字段类型,但不会自动创建UNIQUE INDEX(手工创建会报错)

●方案:OB不支持该index,直迁数据即可(OMS迁移会忽略)。在做对象校验时需要忽略这类index。

create table test001 (
  uinfo clob
);
insert into test001 values ('
{
  "employees":[
    {"firstName":"Bill","lastName":"Gates","creation_time":"2021-01-01","age":"30"},
    {"firstName":"George","lastName":"Bush","creation_time":"2021-06-01","age":"26"},
    {"firstName":"Thomas","lastName":"Carter","creation_time":"2020-03-01","age":"23"}
	]
}           
');
commit;

select * from dba_indexes where table_name='TEST001';


SELECT INDEX_NAME,TABLE_NAME,TABLE_OWNER,DBMS_METADATA.get_ddl('INDEX',INDEX_NAME,'APPTEST') INDEX_DDL
   FROM user_indexes --当前用户下的索引
 WHERE table_name = 'TEST001';
 
-- 对应DDL
  CREATE UNIQUE INDEX "APPTEST"."SYS_IL0000101865C00001$$" ON "APPTEST"."TEST001" (
  PCTFREE 10 INITRANS 2 MAXTRANS 255 
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "USERS" 
  PARALLEL (DEGREE 0 INSTANCES 0) 
相关推荐
程序猿校长2 小时前
SQL小白超详细入门教程
数据库·sql·oracle
Lucifer三思而后行3 小时前
Centos 7.9 一键安装 Oracle 12CR2 单机
后端·oracle
TPBoreas4 小时前
物理删除和逻辑删除区别
数据库·oracle
前端组件开发4 小时前
JeeSite V5.7.1 发布,Java快速开发平台,Spring Boot,Vue3,微服务
java·数据库·spring boot·微服务·oracle·开源
Zonda要好好学习4 小时前
黑马点评DAY1|Redis入门、Redis安装
数据库·redis·oracle
danielli6 小时前
如何设计通用用户、权限、菜单数据表
数据库·oracle
chat2tomorrow6 小时前
oceanbase数据库安装和连接实战(阿里云服务器操作)
数据库·ide·mysql·阿里云·云计算·oceanbase·sqlynx
OceanBase数据库官方博客6 小时前
OceanBase v4.2 特性解析:对Json与Xml的扩展支持
xml·json·oceanbase·分布式数据库·产品特性
虫小宝16 小时前
使用Oracle IMP导入数据
数据库·oracle
&木头人&1 天前
oracle plsql如何debug触发器
数据库·oracle