基于湖库一体架构,统一管理结构化、半结构化与非结构化等多模态数据,一个系统承载事务处理、实时分析与 AI 工作负载。
带局部索引的表 add/drop/truncate 分区后 DML 出现 4377
更新时间:2026-08-26 12:01
基本信息
问题现象
对某些特定行执行 DELETE 或 UPDATE 操作时,必现 4377 错误(OB_ERR_DEFENSIVE_CHECK)。该错误的本质是主表中存在这些行的记录,但对应的索引表中没有。
适用版本
OceanBase 4.4.2 BP1(oceanbase-4.4.2.1-101080012026081217)
问题分析
触发条件
同时满足以下三个条件会导致 Schema 数据不正确,但此时不一定会立即出现 4377 错误:
- 集群使用了 4.4.2 BP1 版本的 observer。
- 存在分区表,且表上建有局部索引。最近一次执行的 DDL 操作是
ALTER TABLE ADD/DROP/TRUNCATE PARTITION等分区变更操作。 - Schema History 的回收发生在上述分区 DDL 操作之后。
错误产生机制
要最终产生 4377 错误,还需要在写入数据时通过延迟校验方式获取 Table Schema,典型场景包括:
- 写入数据时存在远程执行。
- 远程执行的对端机器 Schema 缓存中没有源端机器传递的 Schema Version 对应的信息(可能是源端机器的 Schema 刷新过于落后,或对端机器缓存发生切换等情况)。
解决方案
事前巡检
对于尚未升级到 4.4.2 BP1 的集群:
- 暂停升级。
- 直接升级到 4.4.2 BP1 Hotfix1 版本。
- 无需进行额外处理。
对于已升级到 4.4.2 BP1,但尚未升级到 4.4.2 BP1 Hotfix1 的集群:
请尽快执行以下操作进行规避:
- 记录
schema_history_expire_time配置项的原值,以便后续恢复。 - 在 sys 租户下执行以下命令,调大 Schema History 的过期时间:
ALTER SYSTEM SET schema_history_expire_time = '30d' TENANT = ALL;
- 在 sys 租户下执行以下命令,关闭所有用户租户的 Schema History 回收定时任务(需为每个用户租户单独执行,替换
tenant_name):
CALL DBMS_SCHEDULER.DISABLE('SCHEDULED_RECYCLE_SCHEMA_HISTORY') TENANT = 'tenant_name';
- 在 sys 租户下执行以下 SQL,确定最近一次 Schema History 回收的 Schema Version:
-- VALUE1 列为最近一次回收的 schema version
SELECT * FROM cdb_ob_tenant_event_history
WHERE
tenant_id = xxx -- 租户 id
AND event LIKE '%batch_recycle_by_tenant%'
ORDER BY timestamp DESC LIMIT 1;
- 在 sys 租户下执行以下 SQL,查询可能存在潜在问题的主表:
SELECT DISTINCT t1.tenant_id, t1.table_id, t1.schema_version
FROM oceanbase.__all_virtual_table t1
WHERE EXISTS
(
SELECT 1 FROM oceanbase.__all_virtual_table t2
WHERE
t2.tenant_id = t1.tenant_id
AND t2.data_table_id = t1.table_id
AND t2.schema_version > t1.schema_version
)
AND t1.schema_version < [上一步查询出的回收版本号];
如果查询结果不为空,则说明这些表存在 Schema 不一致的风险。
修复与恢复
- 尽快升级到 4.4.2 BP1 Hotfix1 版本。
- 升级完成后,执行以下恢复操作:
- 在 sys 租户下执行以下命令,将 Schema History 过期时间恢复为原值:
ALTER SYSTEM SET schema_history_expire_time = '原值' TENANT = ALL;
- 在 sys 租户下执行以下命令,重新打开所有用户租户的 Schema History 回收定时任务(需为每个用户租户单独执行,替换 `tenant_name`):
CALL DBMS_SCHEDULER.ENABLE('SCHEDULED_RECYCLE_SCHEMA_HISTORY') TENANT = 'tenant_name';
事后诊断
当出现 4377 错误时,可以通过以下 SQL 进行诊断,确认问题是否由本案例所述原因导致:
-- 诊断 SQL
SELECT DISTINCT t1.tenant_id, t1.table_id, t1.schema_version
FROM oceanbase.__all_virtual_table t1
WHERE EXISTS
(
SELECT 1 FROM oceanbase.__all_virtual_table t2
WHERE
t2.tenant_id = t1.tenant_id
AND t2.data_table_id = t1.table_id
AND t2.schema_version > t1.schema_version
)
AND t1.schema_version < [最近一次回收的 schema version];
如果查询结果不为空,则表明问题符合本案例描述的场景。