查不到px等待事件需用gv$active_session_history,因rac中px进程跨实例分布;关键看time_waited而非sample_count,max(time_waited)>5s表明存在严重并行倾斜。
查不到 px 等待事件?先确认是否用了 gv$active_session_history
在 rac 环境下,v$active_session_history 只记录本实例的采样数据,而并行查询的协调进程(px coordinator)和工作进程(px slave)很可能跨节点运行。如果只查单实例视图,像 px deq: execution message、parallel query dequeue wait 这类关键等待根本不会出现。
必须用 gv$active_session_history,且建议显式按 inst_id 分组比对:
SELECT inst_id, sql_id, event, COUNT(*) cnt FROM gv$active_session_history WHERE sample_time > SYSDATE - 1/1440 AND (event LIKE 'PX %' OR event LIKE 'parallel %') GROUP BY inst_id, sql_id, event ORDER BY cnt DESC;
- 若某
sql_id的等待集中在单一inst_id,说明并行执行未跨节点分布,问题更可能是本地 CPU 或 I/O 资源瓶颈 - 若同一
sql_id在多个inst_id上都有等待,但time_waited差异极大(比如节点2平均 800ms,节点1仅 5ms),就是典型的工作分配不均
time_waited 才是判断倾斜的核心指标,不是 sample_count
ASH 每秒采样一次,COUNT(*) 高只代表“被采到的次数多”,不等于“真卡了那么久”。真正暴露长尾延迟的是 time_waited(单位:微秒),它来自底层等待事件的精确计时。
以下语句能定位最耗时的并行等待样本:
SELECT sql_id, event,
ROUND(AVG(time_waited)/1000, 2) avg_ms,
MAX(time_waited)/1000 max_ms
FROM v$active_session_history
WHERE event IN ('PX Deq: Execution Message',
'PX Deq: Table Q Normal',
'PX qref latch')
AND sample_time > SYSDATE - 1/24
GROUP BY sql_id, event
HAVING MAX(time_waited) > 5000000
ORDER BY max_ms DESC;
-
MAX(time_waited) > 5000000(即 > 5 秒)是硬信号:至少有一个 PX slave 卡住,拖慢整个并行组 - 若
AVG(time_waited)很低但MAX极高,基本可断定是数据分布倾斜或分区裁剪失效,导致某个 slave 扫描远超其他 slave - 别忽略
current_obj#字段:结合dba_objects查出该sql_id正在访问的表,再检查其分区策略和统计信息
为什么 sql_id 显示长时间运行,但实际业务感觉很快?
ASH 记录的是“会话活跃状态”,不是“SQL 执行耗时”。常见误判场景包括:
- SQL 实际执行快,但被阻塞(如
enq: TX - row lock contention)后长时间挂起,ASH 把整个阻塞期都算进“SQL 执行时间” - SQL 被硬解析卡住(比如
library cache lock),ASH 记录的是“parse + execute”总耗时,而你只关心 execute 阶段 - SQL 在 PL/SQL 块里循环调用,ASH 每次采样都落在不同迭代上,看起来像单次执行超长
验证方法:查 v$sql 中该 sql_id 的 elapsed_time / executions 平均值,再对比 cpu_time 和 buffer_gets。如果平均 elapsed_time 是 2ms,但 ASH 里有几十条 30s+ 样本,基本可排除真实执行慢,转向查阻塞或解析问题。
执行计划没变,但某次执行突然巨慢?重点盯绑定变量值
计划没变、统计信息也新,但某次执行突然巨慢——十有八九是绑定变量值触发了数据倾斜。例如:
WHERE status = :b1
当 :b1 = 'A' 时返回 10 行,:b1 = 'Z' 时返回 500 万行,优化器按平均值估算,选了 nested loop,结果一个 slave 处理全部 500 万行。
- 查
v$sql_plan_statistics_all中该sql_id对应各执行的starts和actual_rows,看是否存在某 step 的actual_rows远超其他 step - 结合
dba_tab_histograms看status列是否有严重倾斜的直方图分布 - 临时改写为
WHERE status = /*+ OPT_PARAM('_optim_peek_user_binds', 'false') */ :b1测试是否缓解,确认是否是 bind peeking 导致的误判
并行倾斜的真实瓶颈往往不在 SQL 写法本身,而在数据物理分布与绑定值的隐式耦合——这点最容易被跳过,直接去调优语句反而绕远路。











