基于湖库一体架构,统一管理结构化、半结构化与非结构化等多模态数据,一个系统承载事务处理、实时分析与 AI 工作负载。
Queuing 表频繁在线收集统计信息导致相关 SQL 的执行计划频繁重新生成
更新时间:2026-05-14 07:41
问题现象
在进行性能压测时发现如下的一张普通表上的相同类型的SQL语句在频繁地重新生成执行计划(但生成的执行计划内容却都是一样的),该硬解析行为导致 SQL 整体的响应时间较长。

同时根据 OCP SQL 诊断页面上显示的其中一条 SQL 的 traceId 去 observer.log 中排查,发现有如下的类似日志。
[2025-02-26 18:50:20.429302] INFO [SQL.PC] check_after_get_plan (ob_plan_cache.cpp:546) [3178125][T1006_L0_G0][T1006][xxxxx-xxxxx-xxxxx-xxxxx] [lt=0] the statistics of table is stale and evict plan.(plan->stat_={plan_id:0, sql_text:"delete from tmp_xxx_merge_result where batch_id = ? and ytenant_id=?", raw_sql:"delete from tmp_xxx_merge_result where batch_id = 'xxx' and ytenant_id='xxx'", gen_time:1740567020394424, schema_version:1740539898476376, last_active_time:1740567020395836, hit_count:0, mem_used:282360, slow_count:0, slowest_exec_time:1740567020395836, slowest_exec_usec:94122, execute_times:1, disk_reads:0, direct_writes:0, buffer_gets:38, application_wait_time:0, concurrency_wait_time:0, user_io_wait_time:0, rows_processed:16, elapsed_time:94122, cpu_time:94112, large_querys:0, delayed_large_querys:0, outline_version:1740474935831736, outline_id:1638777, is_evolution:false, is_last_exec_succ:true, is_bind_sensitive:false, is_bind_aware:false, is_last_exec_succ:true, timeout_count:0, evolution_stat:{executions:0, cpu_time:0, elapsed_time:0, error_cnt:0, last_exec_ts:0}, plan_hash_value:8600446970471666667, hints_all_worked:true})
[2025-02-26 18:50:20.739576] INFO [SQL.PC] inner_add_cache_obj (ob_pcv_set.cpp:247) [3178125][T1006_L0_G0][T1006][xxxxx-xxxxx-xxxxx-xxxxx] [lt=1] has identical pcv(is_same=true, pcv=0x7f605e1bc600)
问题原因
日志关键字 the statistics of table is stale and evict plan 的含义是:统计信息严重过期后会主动淘汰执行计划。目前一台 OBServer 上租户的执行计划被淘汰的主要触发机制有下面几种。
原因一: 相关表对象的 schema_version 发生了变更(即该表上执行了 DDL 语句,典型的如增删索引、增删列)。
原因二: 开启了 SPM 且 SPM 对该 SQL 的执行计划进行了在线演进。
原因三: 优化器实际执行后发现查询该非分区表时实际扫描的行数远大于执行计划中预估需要扫描的行数(真实计算方法比较复杂)。
原因四: 相关表上的统计信息重新收集了一次(自动触发或手工收集)。
原因五: 用户主动手工 flush plan cache。
原因六: Plan Cache 内存不足导致了老执行计划的淘汰。
从 SQL Audit 记录中排查该表上实际执行过的 SQL 语句发现,该表基本的使用模式如下所示。
T1: insert into tmp_xxx_merge_result select ...
T2: delete from tmp_xxx_merge_result where ...
T3: insert into tmp_xxx_merge_result select ...
T4: delete from tmp_xxx_merge_result where ...
T5: insert into tmp_xxx_merge_result select ...
T6: delete from tmp_xxx_merge_result where ...
...
...
...
可以发现这是一张非常典型的 Queuing 表用法,即在表上进行了非常频繁的数据插入 + 删除操作。目前当系统变量 _optimizer_gather_stats_on_load 为 True 时,使用 GATHER_OPTIMIZER_STATISTICS Hint 或者 APPEND Hint 或者启动了 PDML 且 DOP>1 时会自动启动在线收集统计信息功能。当前问题环境上开启了 Auto DoP,因此怀疑 Auto DoP 机制导致 insert into tmp_xxx_merge_result select ... 自动获取了一个 DOP>1 进行执行,从而导致该表上重新收集了统计信息。一旦统计信息重新收集过了,根据原因四,就会触发该表上相关执行计划的淘汰。
从系统视图 DBA_OB_TABLE_STAT_STALE_INFO 中也可以发现,该视图中的 LAST_ANALYZED_TIME 一直在频繁更新,与该表频繁在线收集统计信息基本一致,示例如下。
MySQL [xxx]> select * from oceanbase.dba_ob_table_stat_stale_info where database_name='xxx' and table_name='tmp_xxx_merge_result'\G
*************************** 1. row ***************************
DATABASE_NAME: xxx
TABLE_NAME: tmp_xxx_merge_result
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
LAST_ANALYZED_ROWS: 631568
LAST_ANALYZED_TIME: 2025-02-26 20:09:01.779062
INSERTS: 32027
UPDATES: 0
DELETES: 30563
STALE_PERCENT: 10
IS_STALE: NO
1 row in set (0.317 sec)
MySQL [xxx]> select * from oceanbase.dba_ob_table_stat_stale_info where database_name='xxx' and table_name='tmp_xxx_merge_result'\G
*************************** 1. row ***************************
DATABASE_NAME: xxx
TABLE_NAME: tmp_xxx_merge_result
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
LAST_ANALYZED_ROWS: 631984
LAST_ANALYZED_TIME: 2025-02-26 20:09:07.065829
INSERTS: 36778
UPDATES: 0
DELETES: 34634
STALE_PERCENT: 10
IS_STALE: YES
1 row in set (0.313 sec)
MySQL [xxx]> select * from oceanbase.dba_ob_table_stat_stale_info where database_name='xxx' and table_name='tmp_xxx_merge_result'\G
*************************** 1. row ***************************
DATABASE_NAME: xxx
TABLE_NAME: tmp_xxx_merge_result
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
LAST_ANALYZED_ROWS: 632416
LAST_ANALYZED_TIME: 2025-02-26 20:09:12.199433
INSERTS: 41450
UPDATES: 0
DELETES: 39431
STALE_PERCENT: 10
IS_STALE: YES
1 row in set (0.274 sec)
MySQL [xxx]> select * from oceanbase.dba_ob_table_stat_stale_info where database_name='xxx' and table_name='tmp_xxx_merge_result'\G
*************************** 1. row ***************************
DATABASE_NAME: xxx
TABLE_NAME: tmp_xxx_merge_result
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
LAST_ANALYZED_ROWS: 648064
LAST_ANALYZED_TIME: 2025-02-26 20:16:43.011552
INSERTS: 415652
UPDATES: 0
DELETES: 413770
STALE_PERCENT: 10
IS_STALE: YES
1 row in set (0.298 sec)
问题的风险及影响
相同类型的 SQL 语句在频繁地重新生成执行计划,但生成的执行计划内容却都是一样的,该行为导致 SQL 整体的响应时间较长。
影响租户
影响 OceanBase 数据库中的 SYS 租户和 Oracle 租户以及 MySQL 租户。
适用版本
OceanBase 数据库 V4.2.0(oceanbase-4.2.0.0-100000032023071023)及之后版本。
解决方法
方法一: 关闭 Auto DoP。
方法二: 通过为该表的
insert into ... select ...SQL 语句添加NO_GATHER_OPTIMIZER_STATISTICS的 Hint 来关闭统计信息收集。方法三: 通过系统变量
_optimizer_gather_stats_on_load来关闭统计信息的自动收集。
具体采取哪种方法需要评估每种方法的优劣势和可能带来的后果,评估并测试后采取最优的方案来实施。
规避方式
无。