隐式转换本身不产生等待事件,但会导致执行计划错误(如该走索引却全表扫描),进而引发大量db file scattered read;需通过ASH中物理读反向定位SQL,再结合FILTER/ACCESS_PREDICATES中的INTERNAL_FUNCTION或SYS_OP_C2C确认根因。

直接查 v$active_session_history 里带 INTERNAL_FUNCTION 的采样点
隐式转换本身不产生等待事件,但它会让执行计划走错路——比如该走索引却走了全表扫描,进而触发大量 db file scattered read。ASH 不记录“为什么走错”,但会忠实记录“走错后干了什么”。所以不能只盯 FILTER_PREDICATES 字段,得反向从物理读行为切入,再回溯关联的 SQL。
先跑这个语句锁定最近 5 分钟内高频物理读的会话:
SELECT session_id, session_serial#, sql_id, COUNT(*) cnt FROM v$active_session_history WHERE sample_time > SYSDATE - 5/1440 AND event = 'db file scattered read' AND session_type = 'FOREGROUND' GROUP BY session_id, session_serial#, sql_id HAVING COUNT(*) >= 8 ORDER BY cnt DESC;
拿到高频 sql_id 后,立刻查它的执行计划:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('&sql_id', NULL, NULL, 'ADVANCED'));重点扫 ACCESS_PREDICATES 和 FILTER_PREDICATES 列,只要看到 INTERNAL_FUNCTION 或 SYS_OP_C2C,基本就是隐式转换实锤。注意:不是所有含 INTERNAL_FUNCTION 的 SQL 都慢,但凡它出现在 FILTER_PREDICATES 且对应操作是 TABLE ACCESS FULL,就极大概率是问题根因。
current_obj# 为空时更要盯 program 和 machine
当 v$active_session_history 中 current_obj# 为 NULL,说明当时没发生物理读,或者读的是缓存块、或走的是索引路径——但这不等于没隐式转换。很多隐式转换发生在硬解析阶段,还没到物理读那步,current_obj# 就拿不到值。
这时要靠 program 和 machine 定位来源:
-
program是关键线索:比如jdbc thin client、python、sqlplus@prod01,能快速判断是应用层还是 DBA 手动执行 -
machine配合terminal可追溯 IP,确认是不是某个定时脚本在凌晨批量刷数据 - 如果
username是ANONYMOUS或为空,但program明显异常(如load_data.sh),优先怀疑绑定变量类型传错
别指望 current_obj# 总是有值——它只在真实发生物理读时才被填充,而隐式转换的破坏性,往往在解析和执行计划生成阶段就已经埋下了。
用 V$SQL_PLAN 快速筛出所有潜在隐式转换 SQL
不是每次都能等到慢查询发生再抓 ASH。更主动的做法是定期扫描内存中已执行过的 SQL,把有隐式转换痕迹的都捞出来,提前预警。
下面这条语句能覆盖大部分常见场景:
SELECT sql_id, plan_hash_value, sql_text
FROM v$sql_plan p
JOIN v$sql s USING (sql_id)
WHERE p.filter_predicates LIKE '%INTERNAL_FUNCTION%'
OR p.filter_predicates LIKE '%SYS_OP_C2C%'
OR p.access_predicates LIKE '%INTERNAL_FUNCTION%'
OR (p.operation = 'TABLE ACCESS' AND p.options = 'FULL'
AND p.sql_id IN (
SELECT sql_id FROM v$sql_plan
WHERE filter_predicates LIKE '%INTERNAL_FUNCTION%'
GROUP BY sql_id
HAVING COUNT(*) > 1
))
ORDER BY sql_id;说明:
-
SYS_OP_C2C表示字符集隐式转换(比如VARCHAR2和NVARCHAR2比较) -
INTERNAL_FUNCTION是 Oracle 内部对多种隐式转换的统一代号,包括数字/字符串、日期/字符串等 - 如果某条 SQL 在多个执行计划中反复出现
INTERNAL_FUNCTION,说明应用层参数类型不稳定,不是偶发而是模式化问题
别漏掉 NLS_DATE_FORMAT 引发的时间类型隐式转换
时间字段上的隐式转换最隐蔽也最危险。比如表里 create_time 是 DATE 类型,但应用传入的是字符串 '2026-10-27',Oracle 就会按当前会话的 NLS_DATE_FORMAT 去解析——一旦格式不匹配,要么报错,要么走错执行路径。
验证方式很简单:
SELECT value FROM nls_session_parameters WHERE parameter = 'NLS_DATE_FORMAT';
如果返回不是 YYYY-MM-DD HH24:MI:SS 这类标准格式,而你又在 WHERE 条件里写了 create_time = '2026-10-27',那几乎必然触发隐式转换。
真正安全的写法只有两种:
- 用
TO_DATE('2026-10-27', 'YYYY-MM-DD')显式转 - 让应用传
DATE类型参数,数据库层完全不碰字符串
这种问题不会立刻报错,但会在某些会话下悄悄失效索引——尤其当测试环境和生产环境 NLS_DATE_FORMAT 不一致时,排查难度直线上升。


















