可通过DBA_HIST_SQLSTAT与DBA_HIST_SQLTEXT关联,用LAG()计算TEMP_SPACE_ALLOCATED相邻快照差值,结合EXECUTIONS_DELTA>0和SNAP_ID范围筛选高消耗SQL;优先使用ASH(EVENT='direct path write temp')或v$sql_monitor定位,避免依赖v$sort_usage。
怎么从AWR里定位消耗 Temp 的 SQL
awr 本身不直接记录每条 sql 的临时表空间用量,但可以通过 dba_hist_sqlstat 和 dba_hist_sqltext 关联 temp_space_allocated 字段反向筛选。这个字段是累计值(单位字节),且只在 sql 执行结束时才写入快照,所以必须比对相邻两个快照的差值。
常见错误是直接查单次快照里 TEMP_SPACE_ALLOCATED > 0 的 SQL——这会漏掉跨快照执行、或被采样错过结束时刻的语句。
- 用
LAG()窗口函数计算每个SQL_ID在相邻快照间的TEMP_SPACE_ALLOCATED增量 - 限定
SNAP_ID范围,避开数据库刚启动或 AWR 清理后的异常空值 - 过滤掉
EXECUTIONS_DELTA = 0的记录,避免除零或无效归因 - 注意
TEMP_SPACE_ALLOCATED是会话级累计,一条 SQL 并行执行时可能被多个 PX 进程分别上报,需去重或按SQL_ID + PLAN_HASH_VALUE聚合
为什么 v$sort_usage 查不到对应 SQL_ID
v$sort_usage 显示的是当前正在使用临时段的会话和操作,但它里面的 SQL_ID 字段在 Oracle 11.2.0.4 之前经常为空,12c 后虽有改善,但仍依赖 sql_id 是否被成功捕获到 PGA 中。更关键的是:它只反映“此刻”,而高 Temp 消耗往往发生在几秒内完成的排序/哈希连接,等你连上去查,早就释放了。
典型现象是:v$sort_usage 里看到大量 SESSION_NUM,但 SQL_ID 全是空;或者查到 SQL_ID,却在 v$sql 里找不到——说明该游标已被老化出共享池。
- 优先用
v$active_session_history(ASH)回溯,查EVENT = 'direct path write temp'或'read by other session'时的SQL_ID - 如果启用了 SQL Monitoring(
MONITOR = YES),直接查v$sql_monitor的TEMP_SPACE_ALLOCATED实时值 - 别依赖
v$sort_usage.SEGMENT_FILE#去关联dba_temp_files,文件号可能复用,意义不大
Temp 空间暴增但没大排序?检查隐式转换和统计信息
很多情况下,SQL 并没显式 ORDER BY 或 GROUP BY,却占了大量 Temp,根源常是优化器误判——比如谓词中存在隐式类型转换,导致索引失效,被迫走全表扫描+哈希连接;或统计信息陈旧,让优化器低估中间结果集大小,选错执行计划(如该用嵌套循环却选了哈希连接)。
一个典型例子:WHERE col_char = 123(col_char 是 VARCHAR2),触发隐式转 number,索引无法使用,驱动表变大,哈希连接 Build Table 膨胀数倍。
- 查
DBA_HIST_SQL_PLAN中OPERATION含HASH JOIN或SORT的步骤,看BYTES和CARDINALITY预估是否严重偏离实际 - 对比
DBA_TAB_STATISTICS的LAST_ANALYZED时间,尤其关注大表和关联字段 - 用
DBMS_XPLAN.DISPLAY_AWR(SQL_ID, PLAN_HASH_VALUE)看真实 A-Rows 和 E-Rows 差异,差 10 倍以上基本可判定统计问题
AWR 报告里 Temp 使用量和 OS 层 df 不一致?别直接对比
AWR 中的 Temp 使用量来自 v$tempseg_usage 或历史视图聚合,统计的是“已分配但尚未释放”的临时段大小;而 df -h /u01/oradata 显示的是操作系统层面的文件系统剩余空间,包含未格式化的空白块、文件系统元数据、以及临时文件(temp01.dbf)本身的固定大小——哪怕里面全是空闲 extent,df 也不会变。
最常踩的坑是:看到 AWR 说 Temp 消耗 8GB,就以为磁盘快满了,其实 temp 文件可能是 20GB 自动扩展的,当前只用了其中 8GB,df 显示还有 50GB 剩余,完全不冲突。
- 查
dba_temp_files的BYTES和MAXBYTES,确认临时表空间物理上限 - 用
v$temp_space_header(12c+)或v$temp_extent_pool看当前已分配 extent 数量,比 AWR 更实时 - OS 层真正要盯的是
du -sh /path/to/temp01.dbf,不是df——因为 temp 文件不会自动收缩,即使里面全是空闲块
Temp 空间的问题,核心永远不在“用了多少”,而在“谁在用、为什么用、能不能换种方式用”。AWR 提供的是线索,不是答案;真要定位,得把 SQL 执行计划、ASH 样本、临时段分配链路串起来看,少一个环节都容易绕进死胡同。










