查v$active_session_history必须加动态时间窗口和绑定值过滤,因ASH内存仅保留约1小时且高负载下更短;写死时间易漏样,不带绑定值上下文则无法定位绑定变量窥探问题。

查 v$active_session_history 必须加动态时间窗口和绑定值过滤
ASH 内存只保留约 1 小时,高负载下可能更短。写死时间(如 '2026-10-25 14:00:00')极易漏样;绑定变量窥探问题往往只在特定值组合下爆发,不带绑定值上下文,等于盲查。
正确做法是两层过滤:
-
SAMPLE_TIME > SYSDATE - INTERVAL '5' MINUTE—— 精确覆盖最近 5 分钟,不受时区/NLS 影响 -
sql_id IN (SELECT sql_id FROM v$sql WHERE is_bind_sensitive = 'Y' AND is_bind_aware = 'N')—— 锁定已标记为 bind-sensitive 但尚未升级为 bind-aware 的“高危游标”
RAC 环境必须用 gv$active_session_history,否则可能只看到当前节点样本,而问题 SQL 正在 node2 上因 status = 'PENDING' 走索引却卡住。
看 session_state 和 event 组合判断是否真被计划拖垮
绑定变量窥探引发的慢,常表现为“同一条 sql_id,不同 child_number 执行耗时差十倍”。单看 ASH 样本里某条记录耗时 30s,不等于 SQL 本身慢——可能是解析卡住、锁阻塞,或计划完全错配。
关键区分点:
-
session_state = 'ON CPU'且event IS NULL→ 真正在执行,且大概率在走劣质计划(比如全表扫 500 万行) -
session_state = 'WAITING'且event = 'latch: shared pool'→ 正在硬解析,说明绑定变量没生效,UNBOUND_CURSOR = 'Y'在v$sql里可验证 -
session_state = 'WAITING'且event = 'enq: TX - row lock contention'→ 和绑定值无关,先放一边
别只聚合 sql_id:用 GROUP BY sql_id, child_number,再关联 v$sql_plan_statistics_all 看各子游标实际逻辑读/物理读差异。
用 dbms_xplan.display_cursor 对比 peeked_binds 和实际执行计划
绑定变量窥探的本质,是优化器“偷看”第一次传入的值生成计划。要确认是不是它搞的鬼,就得把当时窥探到的值和当前执行的值摊开比。
执行这句:
SELECT * FROM TABLE(dbms_xplan.display_cursor('cuw23huyg926x', NULL, 'outline +peeked_binds'));
重点看两处:
-
Peeked Binds区域:显示首次硬解析时看到的绑定值(比如:b1 = 'PENDING') - 执行计划中是否用了索引扫描?如果用了,再查
v$sql里该sql_id的executions和buffer_gets/executions,若平均逻辑读高达百万级,基本坐实“用索引查了 99% 的 DONE 行”
如果 peeked_binds 是 'DONE' 却走了索引,说明直方图没建对或统计信息过期;如果是 'PENDING' 却走了全表扫描,说明 ACS 没触发或被禁用(检查 _optimizer_adaptive_cursor_sharing 是否为 FALSE)。
验证 ACS 是否真正生效:查 v$sql_cs_histogram 和 v$sql_cs_selectivity
ACS 不是开了就自动万能。它分三步走:bind-sensitive → bind-aware → shareable。中间卡在第一步,就是典型“识别出数据倾斜但没生成新计划”。
运行以下查询:
SELECT sql_id, child_number, bucket_id, count FROM v$sql_cs_histogram WHERE sql_id = 'cuw23huyg926x';<br>SELECT sql_id, child_number, predicate, low, high, bucket_id FROM v$sql_cs_selectivity WHERE sql_id = 'cuw23huyg926x';
如果 v$sql_cs_histogram 里只有 bucket_id = 0 且 count > 100,说明还没进入 bind-aware 阶段;如果 bucket_id 有 0/1/2 多个,但 v$sql_cs_selectivity 里 low/high 范围重叠严重(比如都落在 0.01–0.99),说明直方图粒度不够,ACS 判定不出值域差异。
这时候强行刷新统计信息没用——得先确认 dba_tab_histograms 里该列是否真有高度平衡直方图(num_buckets > 254),没有就补 DBMS_STATS.GATHER_TABLE_STATS(..., method_opt => 'FOR COLUMNS status SIZE SKEWONLY')。
最易忽略的一点:ACS 只对 WHERE 条件中参与选择率计算的列敏感,ORDER BY 或 JOIN 条件里的绑定变量不会触发它。别在错误的地方等自适应。











