OB(Oracle租户)迁移后导致业务查询慢,如何排查?

背景:
客户通过OMS将Oracle核心业务系统迁移至OceanBase4.2。迁移(全量+增量同步)完成后,进入业务跑批验证阶段。业务侧反馈,原本在Oracle上执行仅需120ms的复杂关联报表查询,在OceanBase上飙升到4~6秒,导致前端页面卡顿。

故障现象:
业务报错:应用日志频繁出现 OB_ERR_EXECUTE_TIME_OUT(查询超时),且 OBProxy 日志中记录了 OB_SERVER_IS_WAITING 警告。
OCP监控显示:OceanBase 服务器 CPU 利用率从平稳期的 30% 飙升至 95% 以上,但内存(MemStore)使用率正常(仅 40%),IO 等待极低。
内部视图:查询 GV$SQL_PLAN_MONITOR 发现,该报表 SQL 的执行计划中对一张存量数据达 5000万行 的事实表使用了 TABLE ACCESS FULL(全表扫描),而预期应该使用 UNIQUE INDEX 或 RANGE SCAN。

问题:
如何分析该问题并解决?

2 个赞

优化SQL,估计是索引失效了

1 个赞

【根本原因分析】

  1. OMS迁移时虽然同步了数据,但默认不会自动收集新的统计信息,可能会导致OceanBase优化器(CBO),认为表数据量很小(或列NDV失真),错误地选择了全表扫描。
  2. Oracle与OceanBase的数据类型存在细微差异(如VARCHAR2(10)迁移后变为VARCHAR(10)),若SQL中WHERE条件的绑定变量类型与列类型不严格匹配(如隐式类型转换),可能会触发索引失效。
  3. OceanBase的优化器参数(如optimizer_index_cost_adj)默认值与Oracle不同,可能导致索引成本被高估。

【解决方法】
1、快速恢复业务查询,强制走正确索引,立即降低CPU,恢复响应时间。
1.1、查找消耗CPU最高的TOP SQL(获取SQL_ID)
SELECT sql_id, elapsed_time, cpu_time, executions, plan_hash_value,
rows_processed, substr(query_sql, 1, 100) as sql_preview
FROM GV$OB_SQL_AUDIT
WHERE tenant_id = [你的租户ID]
AND request_time > (SELECT MAX(request_time) - 60000000 FROM GV$OB_SQL_AUDIT) – 最近60秒
ORDER BY cpu_time DESC LIMIT 10;

1.2、查看该SQL当前的详细执行计划(确认是否全表扫描)
EXPLAIN EXTENDED FOR [SQL_ID,或直接粘贴SQL文本];

1.3、通过Outline(执行计划绑定)强制走索引
格式:CREATE OUTLINE outline_name ON sql_id USING HINT /*+ INDEX(table_name index_name) /;
具体示例(假设sql_id为 ‘ABC123’,表名 FACT_TABLE,索引 IDX_BIZ_DATE):
CREATE OUTLINE my_outline_abc ON ‘ABC123’
USING HINT /
+ INDEX(FACT_TABLE IDX_BIZ_DATE) /;
如果表有别名,HINT中必须使用别名,例如:/
+ INDEX(t IDX_BIZ_DATE) */
执行后,该SQL会立即切换执行计划,CPU应会在10秒内显著下降。

1.4、若Outline无法立即生效,加会话级并行HINT应急(DBA直连OBProxy执行查询)
SELECT /*+ INDEX(t IDX_BIZ_DATE) PARALLEL(4) */ … (原有SQL)

2、深度优化
2.1、收集目标表的统计信息
默认采样率在迁移后可能不准确,建议使用100%采样或高采样率重算:
– 收集表统计信息(确保业务低峰期操作,或使用DBMS_STATS)
CALL DBMS_STATS.GATHER_TABLE_STATS(
ownname => ‘[你的租户名或Schema]’,
tabname => ‘FACT_TABLE’,
estimate_percent => 100,
method_opt => ‘FOR ALL COLUMNS SIZE AUTO’,
degree => 8
);

2.2、修复潜在的隐式类型转换问题(防止索引失效)
检查表结构与SQL条件中的数据类型是否匹配:
– 查看表字段类型
DESC FACT_TABLE;
– 查看SQL中WHERE条件(例如 WHERE BIZ_DATE = ‘2026-08-11’,如果字段是DATE类型,
– 而传入的是字符串且无to_date转换,则隐式转换导致索引失效)。
如果发现类型不匹配,有两个办法:
- 最优:联系业务开发修改SQL,显式添加类型转换函数(如 TO_DATE 或 CAST)。
- 过渡方案:在OceanBase中创建基于函数(如 TO_DATE(biz_date))的函数索引(FUNCTION_BASED INDEX)。

2.3、调整优化器相关参数(兼容Oracle习惯)
若业务侧SQL多为复杂关联,可适当调低索引访问成本系数,让优化器倾向使用索引:
– 查看当前值(默认是100,数值越低优化器越倾向走索引)
SHOW PARAMETERS LIKE ‘optimizer_index_cost_adj’;

– 将其调整为 20 或 30(根据实际测试调整)
ALTER SYSTEM SET optimizer_index_cost_adj = 30 TENANT = ‘[租户名]’;

2.4、开启自动统计信息收集任务(防止后续迁移表再次出现此问题)
确保OceanBase的定时维护任务开启;
– 检查状态
SELECT * FROM DBA_SCHEDULER_JOBS WHERE JOB_NAME LIKE ‘%STAT%’;
– 若未开启,执行:
CALL DBMS_SCHEDULER.ENABLE(‘MAINTENANCE_WINDOW_GROUP’);
– 同时设置维护窗口时间为业务低峰期(凌晨2-4点)。

验证方法:再次执行问题SQL,通过 EXPLAIN 确认走索引,观察CPU回落至正常水平。

2 个赞

转积分 社区禁止 还会给积分取消掉