v$sort_usage的sql_id实际对应v$session.prev_sql_id而非当前SQL,易误判“真凶”;应结合ASH中direct path write/read temp事件及v$sql_workarea_active的tempseg_size、multipasses_executions等实时定位真正溢出SQL。
为什么 v$sort_usage 的 sql_id 经常“对不上”
查 v$sort_usage 时看到的 sql_id 实际对应的是会话的 prev_sql_id,不是当前正在跑的语句。只要这个会话之后又执行了别的 sql(哪怕只是 select sysdate from dual),v$sort_usage 里显示的就变成上一条语句——而那条语句可能只是个简单查询,完全不配占几十 gb temp。
根本原因是 v$sort_usage 底层视图定义中直接关联的是 v$session.prev_sql_id,不是 v$session.sql_id。所以靠它找“真凶”,大概率会误判、白忙活。
- 用
SELECT * FROM V$FIXED_VIEW_DEFINITION WHERE view_name = 'V$SORT_USAGE'能验证这个字段来源 - 如果会话当前空闲(
STATUS = 'INACTIVE'),prev_sql_id就是最后执行的语句,但未必是 TEMP 消耗源 - 真正活跃的排序/哈希操作,往往在 ASH 中有更及时、更可靠的采样痕迹
用 ASH 快速抓正在吃 TEMP 的活跃 SQL
ASH(v$active_session_history)每秒采样一次活跃会话,带操作类型和等待事件,比 v$sort_usage 更贴近真实执行现场。关键是要过滤出和 TEMP 直接相关的动作:
- 查
EVENT = 'direct path write temp'或EVENT = 'direct path read temp':说明已在磁盘读写临时段 - 查
SESSION_STATE = 'WAITING'且WAIT_CLASS = 'User I/O',再结合EVENT字段确认是否为 TEMP 类等待 - 加
WHERE SAMPLE_TIME > SYSDATE - 1/24限定最近 1 小时,避免历史噪声
示例语句:
SELECT sql_id, sql_plan_hash_value, event, COUNT(*) cnt
FROM v$active_session_history
WHERE event IN ('direct path write temp', 'direct path read temp')
AND sample_time > SYSDATE - 1/24
GROUP BY sql_id, sql_plan_hash_value, event
ORDER BY cnt DESC;
这个结果里的 sql_id 基本就是正在把数据往 TEMP 写的“现行犯”,不是“前任”。
结合 v$sql_workarea_active 看内存 vs 磁盘执行比例
v$sql_workarea_active 是唯一能告诉你“这个 SQL 的某个操作(SORT/HASH-JOIN)到底有没有溢出到磁盘”的实时视图。它比 ASH 更细粒度,但只反映当前正在运行的工作区。
-
OPERATION_TYPE = 'SORT'且MULTIPASSES_EXECUTIONS > 0→ 多次磁盘往返,排序严重溢出 -
OPERATION_TYPE = 'HASH-JOIN'且TEMPSEG_SIZE > 0→ 哈希构建阶段已落盘 -
OPTIMAL_EXECUTIONS = 0是红色警报:所有工作区都没能在内存完成
常用定位语句:
SELECT sql_id, operation_type, policy,
optimal_executions, onepass_executions, multipasses_executions,
tempseg_size / 1024 / 1024 AS temp_mb
FROM v$sql_workarea_active
WHERE tempseg_size > 1048576
ORDER BY tempseg_size DESC;
注意:该视图只包含“当前正在执行且用了 TEMP”的 SQL,查不到已结束的语句。所以它和 ASH 是互补关系——ASH 看“刚干过什么”,v$sql_workarea_active 看“正在干啥”。
别漏掉 CTE 和子查询的隐式物化
一个看着很短的 SQL,比如带 WITH t AS (SELECT ... ORDER BY ...) 的语句,可能在执行计划里被优化器物化(materialized),然后这个物化过程本身就会触发排序或哈希,占用 TEMP。这类语句在 v$sort_usage 里只会显示 CTE 定义部分,根本看不出问题在哪。
- 用
EXPLAIN PLAN FOR+DBMS_XPLAN.DISPLAY查执行计划,重点看是否有MATERIALIZE或TEMP TABLE TRANSFORMATION - CTE 后面跟
ORDER BY、DISTINCT、GROUP BY,基本等于主动申请 TEMP - 子查询返回行数超过几万、连接列无索引,CBO 很可能放弃
NESTED LOOPS改走HASH JOIN,哪怕你没写JOIN关键字
真正难缠的 TEMP 溢出,往往藏在这些“看起来很安全”的结构里——表面是简单嵌套,背后是哈希分区+多轮落盘。











