大数跨境
0
0

Oracle 迁移到 OceanBase,执行 DDL 立刻引发锁表?

Oracle 迁移到 OceanBase,执行 DDL 立刻引发锁表? 爱可生开源社区
2025-12-10
2
导读:如果你也遇到,有效的民间修复方案。

作者:何文超,分享 MySQL 和 OceanBase 相关技术博文。 个人博客【CSDN | 雅俗数据库】

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 1500 字,预计阅读需要 5 分钟。


1. 故障背景

某客户生产环境从 Oracle 迁移至 OceanBase(文中简称 OB)后,业务投产上线到 OB 侧。

根据业务需求,DBA 在 OB 侧执行扩字段操作,由 varchar2(20) 改为 varchar2(100)。涉及到很简单的一个 DDL 语句(此前在 Oracle 执行多次类似操作,无任何影响),在 OB 执行后,导致业务中断不可用。

1.1 业务影响

  • 应用系统持续反馈 Connection is closed 异常
  • INSERT 的响应耗时增加
  • 无法对 DDL 操作的表进行读写

1.2 紧急处理

  • 杀掉 DDL 会话
  • 业务侧重启应用服务

下面,笔者将通过复现这个故障,来定位故障原因并介绍后续如何规避。

2. 问题复现

2.1 建表并造数

-- 01:建表(采用上述 Oracle 侧的表结构)
CREATETABLE TEST_ONLINE_DDL (
    ID              INT,
    COL_01  VARCHAR2(20)    -- 无约束正常字段             
    COL_02  VARCHAR2(20NOTNULLENABLEVALIDATE,    -- 启用约束且验证
    COL_03  VARCHAR2(20NOTNULLENABLENOVALIDATE,  -- 启用约束不验证历史
);
-- 02: 插入测试数据
INSERTINTO TEST_ONLINE_DDL 
VALUES
  (1'NOVAL_01''VALIDATE_01''NORMAL_北京'),
  (2'NOVAL_02''VALIDATE_02'''),
  (3'NOVAL_03''VALIDATE_03''NORMAL_上海浦东');
COMMIT;
-- 03: 循环执行 n 次
INSERTINTO  TEST_ONLINE_DDL SELECT * FROM TEST_ONLINE_DDL;
COMMIT;

2.2 迁移数据

使用 OMS 将表从 Oracle 迁移到 OB,具体步骤不做阐述。

2.3 表结构对比

迁移后 OB 侧建表语句。

CREATE TABLE"TEST_ONLINE_DDL" (
"ID"NUMBER(*,0),
"COL_01"VARCHAR2(20),
"COL_02"VARCHAR2(20NOTNULLENABLE,
"COL_03"VARCHAR2(20),
CHECK (("COL_03"isnotnull)) ENABLENOVALIDATE
);

对比发现:

数据库
字段定义
Oracle
"COL_03" VARCHAR2(20) NOT NULL ENABLE NOVALIDATE
OceanBase
"COL_03" VARCHAR2(20),
CHECK (("COL_03" is not null)) ENABLE NOVALIDATE

对比 Oracle 与 OB 侧的表结构定义发现:

Oracle 中 COL_03 的 NOT NULL ENABLE NOVALIDATE 属性,在 OB 中被转换为 CHECK (COL_NOVALIDATE is not null) ENABLE NOVALIDATE 约束。

2.4 对比 DDL

DDL 如下:

ALTER TABLE TEST_ONLINE_DDL MODIFY COL_01  VARCHAR2(100);
ALTER TABLE TEST_ONLINE_DDL MODIFY COL_02  VARCHAR2(100);
ALTER TABLE TEST_ONLINE_DDL MODIFY COL_03  VARCHAR2(100);

OB 侧字段扩容对比:

列名
耗时
table_id 是否改变
是否阻塞 DML
COL_01
秒级
未改变
COL_02
秒级
未改变
COL_03
分钟级
改变

3. 问题定位

故障触发机制
故障触发机制

问题的核心源于 迁移工具的结构转换逻辑 与 OceanBase 的 DDL 变更规则 的不兼容。

3.1 OMS 迁移工具的转换规则

OMS 在迁移 Oracle 表结构时,会将列上的 NOT NULL ENABLE NOVALIDATE 属性自动转换为 NOT NULL CHECK 约束(命名类似 %_OBCHECK_%)。这种转换在功能上等价,但 OB 执行 DDL 触发了 Offline DDL 降级规则。

注意:预计在 OMS 4.3.2 版本修复。

3.2 OceanBase 的 DDL 变更规则

对于 CHECK 约束依赖的情况,因用户预期数据发生变长,可能导致不满足 CHECK 约束,OB 会将本应在线的操作(Online DDL)降级为离线操作(Offline DDL)。

特别说明

同类型变长有 CHECK 约束、主键、分区键为 Offline DDL。目前 3.X、4.X 版本皆存在此类问题。

针对 CHECK 约束,后期版本会修复为 Online DDL,目前处于排期中,具体版本官方暂未告知。

离线操作需要重建表结构(table_id发生改变),过程中会持有 MDL 锁,导致所有 DML 操作(如INSERT)阻塞,最终引发业务超时。

注意:对于 CHECK 约束执行 DDL 降级为离线操作(Offline DDL),参考官方文档:列类型变更规则[1]

4. 解决方案

针对上述问题,我们制定了两步修复方案,核心是在 OB 侧将 NOT NULL CHECK 约束还原为原生的列 NOT NULL 属性。

4.1 生成原生 NOT NULL 属性的语句

-- OB 侧生成拼接命令,然后执行命令
select
'ALTER TABLE '||C.OWNER||'.'||C.TABLE_NAME||' MODIFY ('||COL.COLUMN_NAME||' NOT NULL ENABLE NOVALIDATE);'
from
  dba_constraints c 
join
  dba_cons_columns col
on c.constraint_name=col.constraint_name 
and c.table_name=col.table_name 
where c.constraint_type='C'
and c.owner='WMS'
and c.status='ENABLED'
and c.VALIDATED='NOT VALIDATED'
and c.constraint_name like'%_OBCHECK_%'
and c.search_condition like'%is not null%'
orderby c.owner,c.table_name,col.column_name;

4.2 删除冗余的 NOT NULL CHECK 约束

-- OB侧生成拼接命令,然后执行命令
select
'ALTER TABLE '||C.OWNER||'.'||C.TABLE_NAME||' DROP CONSTRAINT '||C.CONSTRAINT_NAME||' ;'
from
  dba_constraints c 
where c.constraint_type='C'
and c.owner='WMS'
and c.status='ENABLED'
and c.VALIDATED='NOT VALIDATED'
and c.constraint_name like'%_OBCHECK_%'
and c.search_condition like'%is not null%'
orderby c.owner,c.table_name;

4.3 操作时间窗口

场景
操作时间
优势
缺点
存在反向链路
正向切换结束、启动反向增量之前
不会反向同步 DDL
压缩割接窗口时间
存在反向链路
启动反向链路后
不影响割接窗口的时间
需要修改OMS组件参数:source.ignoreDdl 设置为 TRUE
无反向链路
业务低峰期操作
业务影响低

5. 如何判断 DDL 操作为在线操作?

为了避免再次发生执行 DDL 导致的锁表问题,DBA 需要检查在 OB 侧执行的 DDL 语句是否为在线操作(Online DDL)。如果不是,则需要在停服期间执行此 DDL 变更。

如何判断 DDL 是否为 Online DDL?

在 OceanBase 中,判断一次 DDL 操作是否为在线操作(Online DDL)的核心依据之一是 表 ID(TABLE_ID)是否发生变化,这也是实践中最直观有效的验证方式。具体操作如下:

5.1 执行 DDL 前查询表 ID

通过 DBA_OB_TABLE_LOCATIONS 视图获取目标表当前的 TABLE_ID

SELECT DISTINCT(TABLE_ID)
FROM DBA_OB_TABLE_LOCATIONS
WHERE TABLE_NAME = '目标表名';

5.2 执行 DDL 操作

例如修改字段长度:

ALTER TABLE 目标表名 MODIFY 字段名 VARCHAR2(新长度);

5.3 执行 DDL 后再次查询表 ID

重复步骤 1 的查询语句,对比前后的 TABLE_ID

  • 若 TABLE_ID 保持不变:说明 DDL 操作是在线执行(Online DDL),未触发表结构重建,不会阻塞 DML 操作。
  • 若 TABLE_ID 发生变化:说明 DDL 操作被降级为离线操作(Offline DDL),过程中会重建表并持有全局锁,可能导致 DML 阻塞。
说明:该方法对表操作和分区操作无效。

更多判断标准可参考 OceanBase 官方文档:如何判断 DDL 操作为在线操作(Online DDL)?[2]

参考资料
[1] 

列类型变更规则: https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002016923

[2] 

如何判断 DDL 操作为在线操作(Online DDL): https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000003980674


本文关键字:#OceanBase #DDL #数据类型


活动推荐:12/20 OceanBase 社区 | SQL 遇上 AI · 上海站


活动安排


  • 时间:2025 年 12 月 20 日(周六)13:00 - 17:30


  • 地点:携程集团总部(上海市长宁区金钟路968号)-16号楼-2F10会议室

立即扫码报名,抢占席位!

图片

活动推荐:seekdb 征文活动


图片





2000 倍性能提升!Semi Join 改写全过程分析
3.X vs 4.X:OceanBase 手动收集统计信息的天壤之别!
一个案例掌握 OMS 校验方式及适用场景
OBLogProxy 在 Binlog 模式下的故障案例解析



✨ Github:https://github.com/actiontech/sqle

📚 文档:https://actiontech.github.io/sqle-docs/

💻 官网:https://opensource.actionsky.com/sqle/

👥 微信群:请添加小助手加入 ActionOpenSource

🔗 商业支持:https://www.actionsky.com/sqle


【声明】内容源于网络
0
0
爱可生开源社区
爱可生开源社区,提供稳定的MySQL企业级开源工具及服务,每年1024开源一款优良组件,并持续运营维护。
内容 1953
粉丝 0
爱可生开源社区 爱可生开源社区,提供稳定的MySQL企业级开源工具及服务,每年1024开源一款优良组件,并持续运营维护。
总阅读1.9k
粉丝0
内容2.0k