【根本原因分析】
- OMS迁移时虽然同步了数据,但默认不会自动收集新的统计信息,可能会导致OceanBase优化器(CBO),认为表数据量很小(或列NDV失真),错误地选择了全表扫描。
- Oracle与OceanBase的数据类型存在细微差异(如VARCHAR2(10)迁移后变为VARCHAR(10)),若SQL中WHERE条件的绑定变量类型与列类型不严格匹配(如隐式类型转换),可能会触发索引失效。
- 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回落至正常水平。