直接查 event = 'direct path write temp' 是定位 oracle 排序/哈希溢出的最快方式;需限定 sample_time 范围并按 sql_id、plan_hash_value 聚合,用 count(*) 统计采样次数更稳定;再通过 dbms_xplan.display_cursor 查执行计划确认溢出操作及 tempspc 列预估。
直接查 event = 'direct path write temp',这是 oracle 排序/哈希溢出写入磁盘的明确信号,比等语句结束再翻 awr 更及时、更准。
v$sort_usage 里的 SQL_ID 不可靠——它来自 v$session.prev_sql_id,一旦会话执行新语句,旧临时段归属就断连了。ASH 的采样是每秒一次,能真实捕获溢出发生的瞬间。
查 direct path write temp 要加时间范围和聚合
不加时间过滤,v$active_session_history 会返回海量历史数据,结果稀释且查询慢;不按 PLAN_HASH_VALUE 聚合,并行 SQL 的多个 PX 进程会把同一执行计划的开销重复计数,误判为多条高消耗 SQL。
- 必须加
sample_time > SYSDATE - 1/24(最近一小时)或更窄,比如- 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 后必须查执行计划确认溢出路径
看到高采样 SQL_ID,别急着优化语句文本。要确认它是否真在走溢出路径,重点看执行计划里有没有物理操作节点:
-
SORT ORDER BY、SORT GROUP BY、SORT AGGREGATE -
HASH JOIN、HASH GROUP BY、HASH UNIQUE -
TEMP TABLE TRANSFORMATION(尤其带大量插入的 WITH 子句)
用 DBMS_XPLAN.DISPLAY_CURSOR 查实时计划:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('abc123xyz', 123456789));
注意看 TempSpc 列:有数值(单位字节)表示该步骤预估需落盘;若为空但实际发生了 direct path write temp,说明 CBO 预估严重偏差。
别指望 temp_space_allocated 在 ASH 里查到
dba_hist_active_sess_history 和 v$active_session_history 根本不存 temp_space_allocated 字段。这个值只存在于 v$tempseg_usage(当前活跃)和 dba_hist_tempseg_usage(AWR 快照),ASH 的 EVENT 列最多记录等待类型,不带字节数。
- 如果你 SELECT 出来
temp_space_allocated IS NULL,不是数据没刷全,是这个字段压根不存在 - 想看“此刻谁占了多少”,用
v$tempseg_usage:SELECT session_addr, sql_id, tablespace, segtype, blocks * (SELECT value FROM v$parameter WHERE name = 'db_block_size') / 1024 / 1024 AS mb FROM v$tempseg_usage ORDER BY mb DESC; - 注意:11g 中
v$tempseg_usage.sql_id是空的,得靠sql_hash_value关联v$sql
临时段争用的真实瓶颈,往往不在“用了多少 MB”,而在并发分配时卡在 enq: TS - contention 或 v$sort_segment 的位图块上。这时候查 temp_space_allocated 数值已经没意义了——得看锁、看 segment 头、看自动扩展是否关闭。











