首批通过分布式安全可靠测评,为关键业务系统打造
流量 SQL 场景使用 SPM 偶现抖动分析
更新时间:2026-05-14 09:21
问题现象
业务切流发现 SQL 偶尔会抖动,排查发现,执行计划不优,同时生成两个执行计划,抖动的 SQL 没有走索引,不走索引需要几十秒,走索引 2ms,一千多张表,很难通过绑定 outline,需要分析原因。
关键诊断信息
基本排查步骤如下。
确定下索引是什么时间加的。
SELECT t. create_time, s. index_name, s. table_name FROM information_schema. TABLES t JOIN information_schema.STATISTICS s ON t. table_name = s. table_name WHERE t. table_name = 'xxxxx';
SQL 中加了这些字符指纹的东西,导致单个 SQL 流量就很低,很晚走索引的计划才进基线
(04-10 14:43:02),这个图能说明,走全表扫的计划2025-02-28都有了,索引是 3 月 7 号建的,因为单个 SQL 的流量太低,一直演进不完。

ocp_monitor@[oceanbase]>select * from __all_virtual_plan_baseline_item where tenant_id = 1002 and sql_id = 'D1F3D1BE6F9BE7B417CA68A261A13C36'\G; *************************** 1. row *************************** tenant_id: 1002 database_id: 534356 sql_id: D1F3D1BE6F9BE7B417CA68A261A13C36 plan_hash_value: 3233871342238735945 gmt_create: 2025-04-10 14:43:02.151916 gmt_modified: 2025-04-10 14:43:02.151916 sys_vars: NULL plan_type: 1 description: NULL origin: 1 db_version: 4.2.5.2 outline_data: /*+BEGIN_OUTLINE_DATA INDEX(@"SEL$1" "T1"@"SEL$1" "idx_user_out_biz_id") OPTIMIZER_FEATURES_ENABLE('4.2.1.10') END_OUTLINE_DATA*/ flags: 27 last_verified: 1744267358794134 last_executed: 1744267358794134 optimizer_cost: -1 executions: 146 elapsed_time: 109438 cpu_time: 94827 origin_sql: /* 2140eeb817442271795794636d10b2/0.5.9.33//34ecad1b/// */select `T1`.`id`,`T1`.`user_id`,`T1`.`user_nick`,`T1`.`other_user_id`,`T1`.`other_user_nick`,`T1`.`detail_id`,`T1`.`out_biz_id`,`T1`.`biz_type`,`T1`.`fc_type`,`T1`.`item_id`,`T1`.`biz_time`,`T1`.`deal_time`,`T1`.`p_trade_id`,`T1`.`trade_id`,`T1`.`quantity`,`T1`.`amount`,`T1`.`proration`,`T1`.`unpay_amount`,`T1`.`bill_cycle`,`T1`.`waiting_pay_date`,`T1`.`fc_user_bill_id`,`T1`.`status`,`T1`.`join_status`,`T1`.`extend_info`,`T1`.`own_sign`,`T1`.`version`,`T1`.`gmt_create`,`T1`.`gmt_modified`,`T1`.`error_message`,`T1`.`mirror_status`,`T1`.`mirror_id`,`T1`.`bill_type`,`T1`.`inner_type`,`T1`.`inner_id`,`T1`.`uk_biz_id`,`T1`.`is_delete`,`T1`.`db_remark`,`T1`.`quantity_d`,`T1`.`amount_d`,`T1`.`unpay_amount_d`,`T1`.`currency`,`T1`.`country`,`T1`.`proration_d`,`T1`.`term_inst_id` from `xxxxxx` `T1` WHERE ((`T1`.`user_id` = 776045324) AND (`T1`.`out_biz_id` = '13551627007075324') AND ((`T1`.`is_delete`) IS NULL OR (`T1`.`is_delete` = 0))) *************************** 2. row *************************** tenant_id: 1002 database_id: 534356 sql_id: D1F3D1BE6F9BE7B417CA68A261A13C36 plan_hash_value: 11986391583431335905 gmt_create: 2025-02-28 11:15:41.374811 gmt_modified: 2025-04-10 14:47:13.245839 sys_vars: NULL plan_type: 1 description: NULL origin: 1 db_version: 4.2.1.10 outline_data: /*+BEGIN_OUTLINE_DATA FULL(@"SEL$1" "T1"@"SEL$1") OPTIMIZER_FEATURES_ENABLE('4.2.1.10') END_OUTLINE_DATA*/ flags: 27 last_verified: 1744265810828417 last_executed: 1744265810828417 optimizer_cost: -1 executions: 4 elapsed_time: 159435677 cpu_time: 159434545 origin_sql: /* 2102ea2017407125343051301d0174/9.17//34ecad1b/// */select `T1`.`id`,`T1`.`user_id`,`T1`.`user_nick`,`T1`.`other_user_id`,`T1`.`other_user_nick`,`T1`.`detail_id`,`T1`.`out_biz_id`,`T1`.`biz_type`,`T1`.`fc_type`,`T1`.`item_id`,`T1`.`biz_time`,`T1`.`deal_time`,`T1`.`p_trade_id`,`T1`.`trade_id`,`T1`.`quantity`,`T1`.`amount`,`T1`.`proration`,`T1`.`unpay_amount`,`T1`.`bill_cycle`,`T1`.`waiting_pay_date`,`T1`.`fc_user_bill_id`,`T1`.`status`,`T1`.`join_status`,`T1`.`extend_info`,`T1`.`own_sign`,`T1`.`version`,`T1`.`gmt_create`,`T1`.`gmt_modified`,`T1`.`error_message`,`T1`.`mirror_status`,`T1`.`mirror_id`,`T1`.`bill_type`,`T1`.`inner_type`,`T1`.`inner_id`,`T1`.`uk_biz_id`,`T1`.`is_delete`,`T1`.`db_remark`,`T1`.`quantity_d`,`T1`.`amount_d`,`T1`.`unpay_amount_d`,`T1`.`currency`,`T1`.`country`,`T1`.`proration_d`,`T1`.`term_inst_id` from `xxxxxx` `T1` WHERE ((`T1`.`user_id` = 4068257372) AND (`T1`.`out_biz_id` = '8097191880067372') AND ((`T1`.`is_delete`) IS NULL OR (`T1`.`is_delete` = 0))) 2 rows in set (0.025 sec)查询演进的次数,3 小时累计不超过 150 次。

解决办法全表扫的基线计划删掉就解决了,后面这个 SQL 就不会生成全表扫的计划。(注意仔细检查 SQL 小心执行)
SELECT dbms_spm.drop_sql_plan_baseline('global_hjbill_cold_backup_ob_0003' ,sql_id, plan_hash_value) FROM oceanbase.__all_plan_baseline_item WHERE tenant_id = 1002 AND outline_data LIKE '%FULL(@"SEL$1" "T1"@%' AND origin_sql LIKE '%hj_fc_bill%';
问题原因
问题的根本原因是由于 SQL 执行计划的生成差计划时间比较早,索引是之后创建的创建。首次计划生成时(2025-02-28),还未建立索引,因此基线计划中只有全表扫描的基线。业务索引是在 3 月 7 日创建的,但由于单个 SQL 的流量非常低(单个 SQL 的流量非常低主要原因是 SQL 中有业务的 SQL 指纹随机值,3 小时内累计不超过 150 次),走索引的计划直到最近才进入基线客户才关注到。此外,由于 SPM(SQL Plan Management)海景计划演进过程中,即使新的计划更优,仍可能有部分流量选择旧的全表扫描计划来执行,这导致了性能的不稳定。
origin_sql: /* 2140eeb817442271795794636d10b2/0.5.9.33//34ecad1b/// */select
问题的风险及影响
全表扫描会导致查询速度显著变慢影响业务的正常运行。
适用版本
OceanBase 数据库 V4.2.1 GA(oceanbase-4.2.1.0-100000182023092722)版本、V4.2.5(oceanbase-4.2.5.0-100000082024102022)版本、V4.3.5(oceanbase-4.3.5.0-100000122024123020)版本。
解决方法
删除全表扫描的基线计划,使优化器能够选择更优的索引扫描计划。在 OceanBase 数据库 V4.2.5 BP2 版本中是如果 3 小时 150 次跑不到就认为演进失败。正在做的调整是取消了超时时间,只要计划没有淘汰能跑到 150 次 SPM 就会接管。
SELECT dbms_spm.drop_sql_plan_baseline ('global_hjbill_cold_backup_ob_0003' ,sql_id, plan_hash_value) FROM oceanbase.__all_plan_baseline_item WHERE tenant_id = 1002 AND outline_data LIKE '%FULL(@"SEL$1" "T1"@%' AND origin_sql LIKE '%hj_fc_bill%';
规避方式
如果开启 SPM,在创建索引后,分析业务 SQL 适合走索引的计划,应该主动删除相关的旧的基线计划(
dbms_spm.drop_sql_plan_baseline),避免 SPM 选择不优的计划。对于流量较低的 SQL,定期检查并优化执行计划,确保其能够利用新创建的索引。