问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

如何将Oracle中的部分不兼容对象迁移到OceanBase

创作时间:
作者:
@小白创作中心

如何将Oracle中的部分不兼容对象迁移到OceanBase

引用
CSDN
1.
https://blog.csdn.net/OceanBaseGFBK/article/details/137113667

在数据库迁移过程中,兼容性问题一直是技术团队面临的重要挑战。本文将重点探讨在将Oracle数据库迁移到OceanBase时遇到的三种不兼容对象的处理策略,包括LOB类数据、disable约束和自动分区表。通过提前发现并处理这些问题,可以有效规避迁移过程中的报错风险。

背景

在推进自研改造的进程中,需要将Oracle数据库迁移至OceanBase(Oracle模式)数据库。尽管OceanBase在Oracle兼容性方面已表现出色,但仍旧存在一些特殊语法或对象需要特别处理。以下是迁移过程中遇到的一些不完全兼容对象及其处理逻辑。

Oracle中LOB类数据迁移到OB时的处理逻辑

Oracle中CLOB和BLOB类型均可达到4G大小(以Oracle 11.2为例),而OceanBase数据库当前版本(3.2.3.x)所支持的大对象数据类型的信息如下表所示:

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

考虑到从Oracle迁移到OceanBase,如果涉及LOB类字段,可能会存在当LOB数据大于48M时数据丢失的问题,需要提前发现这类数据并进行处理。

2.1 找到Oracle中LOB数据最大长度

可以构建一个实验生成CLOB及BLOB类型数据,使用Oracle自带的DBMS_LOB包获取对应类型的最大值。

2.1.1 构建包含LOB类型的数据表
CREATE TABLE t_lob(
    c_ID NUMBER,
    c_clob CLOB,
    c_blob BLOB
);
2.1.2 创建造数据存储过程

随机插入100条记录到t_lob表。

CREATE OR REPLACE PROCEDURE insert_random_lob_data AS
BEGIN
  DECLARE
    l_random_string VARCHAR2(10000);
    l_random_blob BLOB;
  BEGIN
    FOR i IN 1..100 LOOP
      l_random_string := dbms_random.string('U', dbms_random.value(1, 10000));
      dbms_lob.createtemporary(l_random_blob, TRUE);
      dbms_lob.writeappend(l_random_blob, LENGTH(l_random_string), utl_raw.cast_to_raw(l_random_string));
      
      INSERT INTO t_lob(c_ID, c_clob, c_blob)
      VALUES(i, l_random_string, l_random_blob);
      
      dbms_lob.freetemporary(l_random_blob);
    END LOOP;
    COMMIT;
  END;
END;
/
2.1.3 查询该表中CLOB和BLOB字段的最大值
SELECT MAX(DBMS_LOB.GETLENGTH(C_CLOB)) AS LONGEST_CLOB,
       MAX(DBMS_LOB.GETLENGTH(C_BLOB)) AS LONGEST_BLOB
  FROM T_LOB;

2.2 获取整个数据库中LOB字段值较大的清单

排除了系统用户,获取LOB字段清单后再基于清单中的LOB字段单独分析其最大值。

SELECT COL.OWNER,
       COL.TABLE_NAME,
       COL.COLUMN_NAME,
       COL.DATA_TYPE,
       COL.AVG_COL_LEN,
       COL.CHAR_LENGTH,
       TAB.NUM_ROWS
  FROM DBA_TABLES TAB, DBA_TAB_COLUMNS COL
 WHERE TAB.OWNER = COL.OWNER
   AND TAB.TABLE_NAME = COL.TABLE_NAME
   AND COL.DATA_TYPE IN ('CLOB', 'BLOB')
   AND COL.OWNER NOT IN ('SYS', 'SYSTEM')
   AND COL.OWNER IN
       (SELECT USERNAME FROM DBA_USERS WHERE ACCOUNT_STATUS = 'OPEN')
   AND COL.TABLE_NAME NOT LIKE 'BIN%';

Oracle中disable约束在OMS迁移过程中的处理逻辑

在对Oracle中的约束类非表对象做一致性校验时,发现部分约束在OMS迁移完成后丢失了,需要分析其OMS丢失的原因。

3.1 问题分析

从OMS界面中获取DDL的语句可以看到有2个WARN,且类型是DISCARD,表示OMS判断其是DISABLE状态的约束,直接选择了舍弃掉。

-- [WARN] [DISCARD] CONSTRAINT "PK_T_PARTKEY_IS_PK" PRIMARY KEY ("CRT_DTTM") DISABLE NOVALIDATE -> [NULL]
-- [WARN] [DISCARD] CHECK ("ACT_ID" IS NOT NULL) DISABLE NOVALIDATE -> [NULL]
CREATE TABLE "T_PARTKEY_IS_PK" (
    "ACT_ID" NUMBER(10,0),
    "SRT_ID" NUMBER(10,0),
    "SRT_ORIGNAL_ID" NUMBER(10,0),
    "CRT_DTTM" DATE,
    "LASTUPT_DTTM" DATE
)

3.2 问题结论

Oracle侧处于DISABLE状态的约束通过OMS迁移时会被舍弃,不会在OB侧创建,在对约束对象比对时,需要额外注意Oracle端约束的status是否处于DISABLE状态,本身对业务和功能没有影响。

3.3 约束校验时提前排除DISABLE的约束

可以通过以下语句观测源端Oracle约束状态。

-- 手工将T_PARTKEY_IS_PK表的约束都disable
ALTER TABLE ZHENXING.T_PARTKEY_IS_PK DISABLE NOVALIDATE CONSTRAINT PK_T_PARTKEY_IS_PK;
ALTER TABLE ZHENXING.T_PARTKEY_IS_PK DISABLE CONSTRAINT SYS_C0011109;
SELECT OWNER,
       TABLE_NAME,
       CONSTRAINT_NAME,
       CONSTRAINT_TYPE,
       INDEX_NAME,
       STATUS
  FROM DBA_CONSTRAINTS
 WHERE OWNER = 'ZHENXING'
   AND TABLE_NAME = 'T_PARTKEY_IS_PK';

Oracle中分区表迁移到OB后,带有的自动分区属性丢失

自动分区属性是Oracle 11g的特性,可以用INTERVAL语法基于天、月、年做自动分区创建。在通过OMS迁移到OB后,发现自动分区属性丢失了,会导致当分区未自动创建时导致新增数据没法写入分区表,导致报错。

4.1 问题分析

从OMS界面中获取DDL的语句可以看到有1个WARN,且类型是DISCARD,表示OMS判断其不完全兼容,直接选择了舍弃掉。

-- OMS迁移表结构时记录的WARN信息,表示自动分区属性由于不兼容会自动DISCARD舍弃
[WARN] [DISCARD]  INTERVAL (NUMTOYMINTERVAL (1,'MONTH')) -> [NULL]

4.2 问题结论

所以在Oracle迁移到OB前,需要把Oracle端存在自动分区属性的表提前找出,避免由于迁移到OB后分区为未自动创建导致的数据无法插入的报错,并且找出这类分区后,先在Oracle端创建足够的多分区,避免迁移过程中源端分区数增加导致比对不一致的情况。并记录清单告知业务开发待后续用其他方式定期生成新分区。

4.3 如何找出Oracle中自动分区的表

4.3.1 Oracle侧模拟自动分区
-- 创建基于天的自动分区表
SQL> create table interval_sales (
    prod_id number(6),
    time_id date)
    partition by range (time_id)
    INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
    (partition p1 values less than (to_date('2015-01-01','yyyy-mm-dd')));
-- 查询当前分区,默认生成了1个定义好的分区
SQL> SELECT TABLE_NAME, PARTITION_NAME
  FROM USER_TAB_PARTITIONS
 WHERE TABLE_NAME = 'INTERVAL_SALES';
TABLE_NAME                       PARTITION_NAME
------------------------------ ------------------------------
INTERVAL_SALES                       P1
-- 插入数据(不在默认分区内)
SQL> INSERT INTO INTERVAL_SALES VALUES(001, TO_DATE('2015-02-01', 'yyyy-mm-dd'));
-- 自动生成了新分区
TABLE_NAME                       PARTITION_NAME
------------------------------ ------------------------------
INTERVAL_SALES                       P1
INTERVAL_SALES                       SYS_P221
-- 单独查看该分区数据(验证数据确实存在新分区)
SQL> SELECT * FROM INTERVAL_SALES PARTITION(SYS_P221);
   PROD_ID TIME_ID
---------- ---------
         1 01-FEB-15
4.3.2 统计Oracle侧有哪些表是自动分区的表
/*
PARTITION_COUNT: Number of partitions in the table. For interval partitioned tables, the value of this column is always 1048575.
*/
SELECT T1.OWNER,
       T1.TABLE_NAME,
       T1.INTERVAL,
       T1.PARTITIONING_TYPE,
       T1.PARTITION_COUNT,
       T1.SUBPARTITIONING_TYPE      AS SUB_TYPE,
       T1.SUBPARTITIONING_KEY_COUNT SUB_COUNT,
       T1.STATUS
  FROM DBA_PART_TABLES T1
 WHERE 1 = 1
   AND TABLE_NAME NOT LIKE 'BIN%'
   AND (INTERVAL IS NOT NULL OR PARTITION_COUNT = 1048575);

总结

以上总结分析了3种Oracle对象和OB对象不兼容时的处理方法和提前统计发现的操作方式,在迁移前提前发现这类问题能有效避免在迁移过程中报错的问题。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号