最快定位方式是查EVENT = 'direct path write temp',因ASH每秒采样能捕获几秒内发生的临时表空间暴涨,需限定sample_time范围、按SQL_ID与PLAN_HASH_VALUE聚合,并用COUNT(*)排序采样次数。

直接查 EVENT = 'direct path write temp' 是最快定位方式
临时表空间暴涨往往发生在几秒内,等语句执行完再翻 AWR 或查 v$sort_usage 基本来不及。EVENT = 'direct path write temp' 是 Oracle 将排序/哈希结果写入临时文件的明确信号,ASH 每秒采样一次,能真实捕获溢出发生的瞬间。
常见错误是只查 EVENT LIKE '%temp%' 或漏加时间过滤——不加 sample_time 条件,v$active_session_history 会返回数万行历史数据,查询慢且结果稀释;不按 PLAN_HASH_VALUE 聚合,并行 SQL 的多个 PX 进程会把同一执行计划重复计数,误判为多条高消耗 SQL。
- 必须限定时间范围,例如
sample_time > SYSDATE - 1/144(最近 10 分钟) - 必须
GROUP BY SQL_ID, PLAN_HASH_VALUE,不能只按SQL_ID - 统计用
COUNT(*)(采样次数)比SUM(DELTA_TIME)更稳定,因为短事件中DELTA_TIME常为 0 或被合并
示例查询:
SELECT SQL_ID, PLAN_HASH_VALUE, COUNT(*) samples FROM v$active_session_history WHERE EVENT = 'direct path write temp' AND sample_time > SYSDATE - 1/144 GROUP BY SQL_ID, PLAN_HASH_VALUE ORDER BY samples DESC FETCH FIRST 10 ROWS ONLY;
查到 SQL_ID 后必须用 DBMS_XPLAN.DISPLAY_CURSOR 看执行计划
看到高采样 SQL_ID,别急着改 SQL 文本。要确认它是否真在走溢出路径,重点看执行计划里有没有物理操作节点:SORT ORDER BY、HASH JOIN、HASH GROUP BY、TEMP TABLE TRANSFORMATION(尤其带大量插入的 WITH 子句)。
TempSpc 列是关键:有数值(单位字节)表示该步骤预估需落盘;若为空但实际发生了 direct path write temp,说明 CBO 预估严重偏差——这比语句本身更危险,意味着优化器对中间结果集大小完全失准。
执行命令:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('abc123xyz', 123456789));- 如果计划里没出现上述物理操作,但仍有大量
direct path write temp,大概率是隐式类型转换或统计信息陈旧导致优化器选错路径 - 注意:不要依赖
v$sort_usage.SQL_ID,它来自v$session.prev_sql_id,一旦会话执行新语句,归属就断连了
别指望 temp_space_allocated 字段出现在 ASH 中
dba_hist_active_sess_history 和 v$active_session_history 根本不存 temp_space_allocated 字段——这是个常见误解。AWR 的 DBA_HIST_SQLSTAT 里才有这个字段,但它只在 SQL 执行结束时才写入快照,且是累计值,必须用 LAG() 计算相邻快照差值才能反推单次消耗。
也就是说,ASH 能告诉你“谁在什么时候干了什么”,但不会告诉你“这次干了多少”。想量化临时空间用量,只能回退到 AWR 快照分析,或者启用 SQL Monitoring 查 v$sql_monitor.TEMP_SPACE_ALLOCATED(仅限已开启 MONITOR = YES 的语句)。
- 临时表空间暴涨却没大排序?优先检查谓词中的隐式转换,比如
WHERE col_char = 123(col_char是VARCHAR2) - 并行 SQL 的
TEMP_SPACE_ALLOCATED可能被多个 PX 进程分别上报,需按SQL_ID + PLAN_HASH_VALUE去重聚合
临时表空间文件本身不释放,但监控要看真实使用而非文件大小
Oracle 的临时表空间文件(tempfile)在 sort 结束后只是标记为 free,不会自动收缩。所以 dba_temp_files.bytes 显示的是文件当前大小,不是实时使用量;而 v$tempseg_usage 或 gv$tempseg_usage(RAC 下)才反映当前正在使用的临时段。
一个典型误导现象是:临时表空间文件涨到 20GB,但 v$tempseg_usage 里 sum(used_blocks) 换算后只有几百 MB——说明历史峰值撑大了文件,但当前并无压力。这时候盲目扩容或收缩都可能引发问题。
- 查当前真实使用:
SELECT SUM(used_blocks) * (SELECT value FROM v$parameter WHERE name = 'db_block_size') FROM v$tempseg_usage; - 查文件是否 autoextensible:
SELECT tablespace_name, file_name, autoextensible FROM dba_temp_files; - 文件撑大后,即使业务已平稳,SMON 也不会自动回收空间,除非手动
ALTER DATABASE TEMPFILE ... RESIZE


















