首批通过分布式安全可靠测评,为关键业务系统打造
OceanBase 数据库 V4.3.5 版本中存在大量 OUT-ROW LOB 数据导致表级恢复一张表的速度缓慢
更新时间:2026-05-13 07:31
问题现象
在 OceanBase 数据库 V4.3.5 版本中使用表级恢复功能恢复一张有大量外联存储 OUT-ROW LOB 数据的表,表级恢复存在恢复性能较差、恢复速度较慢问题。 若恢复采用的备份数据的备份介质延迟较高,上述表级恢复的性能问题还会被进一步放大。
LOB 数据说明:
LOB 数据的存储方式包括内联存储(IN-ROW)和外联存储(OUT-ROW)两种;LOB 数据是内联还是外联存储,取决于 LOB 列的数据量。LOB 数据的数据量长度超过设置的阈值,则为外联存储,否则为内联存储。内联存储 LOB 将 LOB 数据存储在主表,外联存储 LOB 将 LOB 数据存储在 LOB 辅助表。 读取外联存储 LOB 数据时:
需要先读取主表行,获取外联 LOB 的定位符(
LOB locator)。再根据定位符
LOB locator信息去 LOB 辅助表中读取实际的 LOB 数据 读取 LOB 数据的这个过程中需要至少需要进行两次存储访问。
关键诊断信息
触发条件
表级恢复恢复的目标存在大量的外联存储(OUT-ROW)的 LOB 数据。
事前巡检
表级恢复执行的过程,通过表级恢复任务视图,查看每张具体的表的恢复任务状态信息,找到 STATUS 处于 DOING 状态的表。
SELECT * FROM oceanbase.CDB_OB_IMPORT_TABLE_TASKS WHERE STATUS = 'DOING'\G提取 task 的 task_id,如下:
obclient(root@sys)[oceanbase]> SELECT * FROM CDB_OB_IMPORT_TABLE_TASKS WHERE STATUS = 'DOING'\G *************************** 1. row *************************** TENANT_ID: 1002 TASK_ID: 464 JOB_ID: 2 SRC_TENANT_ID: 1004 SRC_TABLESPACE: NULL SRC_TABLEGROUP: NULL SRC_DATABASE: test SRC_TABLE: test_table SRC_PARTITION: NULL TARGET_TABLESPACE: NULL TARGET_TABLEGROUP: NULL TARGET_DATABASE: recover_test TARGET_TABLE: test_table TABLE_COLUMN: 4 STATUS: DOING START_TIMESTAMP: 2025-08-11 17:28:22.970334 COMPLETION_TIMESTAMP: ********* CUMULATIVE_TS: -1 TOTAL_INDEX_COUNT: 0 IMPORTED_INDEX_COUNT: 0 FAILED_INDEX_COUNT: 0 TOTAL_CONSTRAINT_COUNT: 0 IMPORTED_CONSTRAINT_COUNT: 0 FAILED_CONSTRAINT_COUNT: 0 TOTAL_REF_CONSTRAINT_COUNT: 0 IMPORTED_REF_CONSTRAINT_COUNT: 0 FAILED_REF_CONSTRAINT_COUNT: 0 RESULT: SUCCESS COMMENT: 1 row in set (0.006 sec)查看表级恢复的 DDL 任务状态。
SELECT * FROM oceanbase.__ALL_ROOTSERVICE_EVENT_HISTORY WHERE MODULE = 'ddl scheduler' AND VALUE4=$task_id;查看最新的
extra_info字段为 REDEFINITION,表示表级恢复处于主表补数据状态。 RS 表级恢复调度没有出现重试和报错信息:obclient(root@sys)[oceanbase]> SELECT * FROM oceanbase.__ALL_ROOTSERVICE_EVENT_HISTORY WHERE MODULE = 'ddl scheduler' AND VALUE4='464'; +----------------------------+---------------+-------------------------------------+-----------+--------+-------+--------+----------+------------------------------------+---------+--------+-----------+-------------------------------------------+------------------+---------------------+------------------------------+--------------+-------------+ | gmt_create | module | event | name1 | value1 | name2 | value2 | name3 | value3 | name4 | value4 | name5 | value5 | name6 | value6 | extra_info | rs_svr_ip | rs_svr_port | +----------------------------+---------------+-------------------------------------+-----------+--------+-------+--------+----------+------------------------------------+---------+--------+-----------+-------------------------------------------+------------------+---------------------+------------------------------+--------------+-------------+ | 2025-08-11 17:28:23.097656 | ddl scheduler | switch_state | tenant_id | 1002 | ret | 0 | trace_id | xxxxxxxxxxxxx-xxxxxxxxxxxxxxxx-x-x | task_id | 464 | object_id | object_id:500008, target_object_id:500003 | snapshot_version | 0 | OBTAIN_SNAPSHOT | x.xx.xxx.xxx | 34000 | | 2025-08-11 17:28:23.110459 | ddl scheduler | switch_state | tenant_id | 1002 | ret | 0 | trace_id | xxxxxxxxxxxxx-xxxxxxxxxxxxxxxx-x-x | task_id | 464 | object_id | object_id:500008, target_object_id:500003 | snapshot_version | 1754904503103015000 | REDEFINITION | x.xx.xxx.xxx | 34000 | +----------------------------+---------------+-------------------------------------+-----------+--------+-------+--------+----------+------------------------------------+---------+--------+-----------+-------------------------------------------+------------------+---------------------+------------------------------+--------------+-------------+ 7 rows in set (0.002 sec)查看恢复的源表是否包含大量的 OUT-ROW LOB 数据。
3.1 通过以下命令查看辅助租户的 tenant_id。
SELECT TENANT_ID,TENANT_NAME FROM oceanbase.__ALL_TENANT WHERE TENANT_NAME IN(SELECT AUX_TENANT_NAME FROM oceanbase.CDB_OB_RECOVER_TABLE_JOB_HISTORY WHERE TENANT_ID= 1)\G示例如下:
obclient(root@sys)[oceanbase]> SELECT TENANT_ID,TENANT_NAME FROM oceanbase.__ALL_TENANT WHERE TENANT_NAME IN(SELECT AUX_TENANT_NAME FROM oceanbase.CDB_OB_RECOVER_TABLE_JOB_HISTORY WHERE TENANT_ID= 1)\G *************************** 1. row *************************** tenant_id: 1004 tenant_name: AUX_RECOVER$17549044441529363.2 通过以下命令查看目标 OUT-ROW LOB 数据量, 其中 $src_table_name 恢复的源表表名,$aux_tenant_id 为辅助租户的 tenant_id。
SELECT SUM(ROW_COUNT) AS total_row_count,SUM(MICRO_BLOCK_COUNT) AS total_micro_block_count,COUNT(*) AS total_macro_block_count FROM oceanbase.__ALL_VIRTUAL_TABLET_SSTABLE_MACRO_INFO WHERE TENANT_ID = $aux_tenant_id AND TABLET_ID IN (SELECT TABLET_ID FROM oceanbase.__ALL_VIRTUAL_TABLET_TO_TABLE_HISTORY WHERE TABLE_ID IN (SELECT TABLE_ID FROM oceanbase.__ALL_VIRTUAL_TABLE WHERE TENANT_ID = $aux_tenant_id AND DATA_TABLE_ID IN (SELECT TABLE_ID FROM oceanbase.__ALL_VIRTUAL_TABLE WHERE TENANT_ID = $aux_tenant_id AND TABLE_NAME = '$src_table_name') AND TABLE_TYPE = 13) AND IS_DELETED=0);示例如下:
obclient> SELECT SUM(ROW_COUNT) AS total_row_count,SUM(MICRO_BLOCK_COUNT) AS total_micro_block_count,COUNT(*) AS total_macro_block_count FROM oceanbase.__ALL_VIRTUAL_TABLET_SSTABLE_MACRO_INFO WHERE TENANT_ID =1002 AND TABLET_ID IN(SELECT TABLET_ID FROM oceanbase.__ALL_VIRTUAL_TABLET_TO_TABLE_HISTORY WHERE TABLE_ID IN (SELECT TABLE_ID FROM oceanbase.__ALL_VIRTUAL_TABLE WHERE TENANT_ID = 1002 AND DATA_TABLE_ID IN(SELECT TABLE_ID FROM oceanbase.__ALL_VIRTUAL_TABLE WHERE TENANT_ID 1002 AND TABLE_NAME = 'kafka_messages_optimized_1') AND TABLE_TYPE = 13)); +-----------------+-------------------------+-------------------------+ | total_row_count | total_micro_block_count | total_macro_block_count | +-----------------+-------------------------+-------------------------+ | 2639267 | 438997 | 2758 | +-----------------+-------------------------+-------------------------+ 1 row in set (0.85 sec)OUT-ROW LOB 数据量 = 微块数量 total_macro_block_count
*16K 左右(关注微块数量)。 如果 OUT-ROW LOB 微块数量很多,比如这里有 43 万个微块,则进一步往下分析。通过
SELECT * FROM GV$OB_FUNCTION_IO_STAT ORDER BY IO_DELAY_US DESC LIMIT 10;命令查看用户的 IO 情况获取 IO 延迟较大模块,REMOTE READ的 RT 较大。 如下表中每个 IO 延迟超过 20ms 说明备份介质性能很差。obclient> SELECT * FROM GV$OB_FUNCTION_IO_STAT ORDER BY IO_DELAY_US DESC LIMIT 10; +---------------+----------+-----------+-----------------+-------------+-------+-----------+-----------+-------------+-------------+----------+ | SVR_IP | SVR_PORT | TENANT_ID | FUNCTION_NAME | MODE | SIZE | REAL_IOPS | REAL_MBPS | SCHEDULE_US | IO_DELAY_US | TOTAL_US | +---------------+----------+-----------+-----------------+-------------+-------+-----------+-----------+-------------+-------------+----------+ | xxx.xx.xx.xxx | 34000 | 1004 | OTHER_GROUPS | REMOTE READ | 12648 | 21 | 0 | 9 | 22189 | 22213 | | xxx.xx.xx.xxx | 34000 | 1002 | OTHER_GROUPS | LOCAL WRITE | 4096 | 2 | 0 | 8 | 155 | 167 | | xxx.xx.xx.xxx | 34000 | 1 | CLOG_HIGH | LOCAL WRITE | 4915 | 5 | 0 | 11 | 85 | 116 | | xxx.xx.xx.xxx | 34000 | 1003 | CLOG_HIGH | LOCAL WRITE | 4588 | 25 | 0 | 6 | 76 | 95 | | xxx.xx.xx.xxx | 34000 | 1001 | CLOG_HIGH | LOCAL WRITE | 4681 | 14 | 0 | 6 | 74 | 93 | | xxx.xx.xx.xxx | 34000 | 1002 | CLOG_HIGH | LOCAL WRITE | 4617 | 55 | 0 | 6 | 73 | 92 | | xxx.xx.xx.xxx | 34000 | 1 | HA_HIGH | LOCAL WRITE | 0 | 0 | 0 | 0 | 0 | 0 | | xxx.xx.xx.xxx | 34000 | 1 | OTHER_GROUPS | REMOTE READ | 0 | 0 | 0 | 0 | 0 | 0 | | xxx.xx.xx.xxx | 34000 | 1 | COMPACTION_HIGH | LOCAL WRITE | 0 | 0 | 0 | 0 | 0 | 0 | | xxx.xx.xx.xxx | 34000 | 1 | COMPACTION_HIGH | REMOTE READ | 0 | 0 | 0 | 0 | 0 | 0 | +---------------+----------+-----------+-----------------+-------------+-------+-----------+-----------+-------------+-------------+----------+ 10 rows in set (0.00 sec)
事后诊断
不涉及。
问题原因
Oceanbase 数据库 V4.x 版本中表级恢复整体流程分为三步骤:
物理恢复辅助租户:从备份数据中恢复辅助租户到指定时间点。
跨租户导表:将指定的表结构、数据及表关联的 schema,从辅助租户导入到目标租户的过程。
清理辅助租户:释放辅助租户占用的资源。
其中步骤 1 和 2 展开论述如下。
物理恢复租户辅助阶段:V4.3.5 BP1 版本开始恢复辅助租户默认使用快速恢复。
跨租户导表阶段:目标端通过 SQL 查询读取源端的数据,SQL 查询默认按照微块粒度读取数据;基于快速恢复恢复辅助租户的表级恢复,辅助租户是通过快速恢复创建的租户,SQL 查询读源租户数据直接读取的是备份介质中的微块;SQL 读取 OUT-ROW LOB 数据存在大量的随机读取;若恢复目标表中存在有大量 OUT-ROW LOB 数据,读取源端数据会耗费大量的时间。 若备份介质的延迟较高,表级恢复的性能问题还将进一步被放大。
问题的风险及影响
表级恢复恢复速度慢。
影响租户
影响 OceanBase 数据库中的 Oracle 租户和 MySQL 租户,对于 SYS 租户无影响。
影响版本
OceanBase 数据库企业版 V4.3.5 BP1(oceanbase-4.3.5.1-101000292025030623)及之后版本。
解决方法
升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V4.3.5 BP3(oceanbase-4.3.5.3-103000102025071821)及之后版本。
可以在使用表级恢复功能恢复一张/组的表之前或执行表恢复过程中,通过执行以下命令提升表级恢复并行度,一定程度加快表级恢复的恢复速度。
# 增加 OBServer 节点上表级恢复工作线程数 ALTER SYSTEM SET ddl_thread_score=INT tenant=$tenant_name; # 增加恢复单张表的并行度 ALTER SYSTEM SET recover_table_dop=INT tenant=$tenant_name;建议将 OceanBase 数据库版本升级到 V4.3.5 BP4 版本,在 V4.3.5 BP4 版本中表级恢复功能支持用户自己选择恢复辅助租户的方式,支持选项全量恢复/快速恢复辅助租户。对于恢复的目标表存在大量 OUT ROW LOB 数据的场景,备份介质延迟较高的场景,建议选择基于全量恢复的表级恢复,具体原因如下:
物理恢复恢复辅助租户阶段:基于全恢复的表级恢复通过全量物理恢复辅助租户读取备份介质宏块到本地。
跨租户导表阶段:通过读本地租户的微块 规避 基于快速恢复辅助租户表级恢复跨租导表阶段大量读取备份介质远程微块,获取源端辅助租户数据性能差的问题。
规避方式
全量物理恢复恢复一个租户;通过工具将表级恢复的目标表结构和数据导出到外部;将表结构和数据导入到目标租户;相关的导入/导出工具,详情参见:如何快速使用导数工具。