不能,ASH不记录syscall等系统调用,仅捕获Oracle数据库层活动;需先通过ASH识别高上下文切换会话(如wait_class='Scheduler'或短时ON CPU),再用perf、pidstat等OS工具定位具体系统调用。
ASH能直接看到系统调用吗?不能,得绕一步
ash(gv$active_session_history)本身不记录syscall、read、write这类操作系统级调用。它只捕获oracle进程在db层的活动快照:sql执行、等待事件、会话状态等。所谓“通过ash定位系统调用”,其实是借力打力——先用ash锁定高上下文切换的会话/sql,再结合os工具(如perf、pidstat -w)确认该pid是否真在频繁陷入内核。
怎么从ASH发现上下文切换压力大的会话?看session_state和wait_class
高频率的上下文切换往往伴随大量短时等待或CPU争抢,ASH里两个字段最敏感:
-
session_state = 'WAITING'且wait_class = 'Scheduler':说明会话被OS调度器挂起,可能因CPU资源不足或抢占激烈 -
session_state = 'ON CPU'但样本间隔极短(比如连续几条记录时间戳差sql_id频繁切换:暗示线程在不同SQL间快速轮转,加剧调度开销 - 查
event为resmgr:cpu quantum或PGA memory operation:前者是资源管理强制yield,后者常触发内存分配系统调用
示例查询(找最近5分钟内CPU态样本最密集的会话):
SELECT session_id, session_serial#, sql_id, COUNT(*) samples FROM gv$active_session_history WHERE sample_time > SYSDATE - 5/1440 AND session_state = 'ON CPU' GROUP BY session_id, session_serial#, sql_id ORDER BY samples DESC FETCH FIRST 5 ROWS ONLY;
为什么DB CPU等待事件高,不一定代表CPU瓶颈?
DB CPU在ASH中表示会话处于Oracle用户态+内核态的总耗时,但它混入了大量非纯计算行为:
- 频繁软解析 → 触发
latch: shared pool争抢 → 持锁期间可能被OS抢占 → 增加调度切换 - 大量小IO(如单块索引扫描)→ 每次
pread都需陷入内核 → 即使IO快,syscall开销也累积成上下文切换压力 - 绑定变量未复用 → SQL硬解析多 →
library cache lock等待 → 线程反复挂起/唤醒
所以看到DB CPU占比高,先别急着加CPU,用pidstat -w -p <pid> 1盯住对应进程的cswch/s(context switch per second),超过5k就要怀疑是不是Oracle内部争抢或低效调用模式导致的。
减少上下文切换的关键实操点:避开隐式系统调用陷阱
很多上下文切换不是业务逻辑导致的,而是Oracle配置或SQL写法触发了不必要的内核交互:
- 禁用
filesystemio_options = 'SETALL'(尤其在EXT4/XFS上):它强制所有IO走direct IO,每次open/close都引发syscall,改用'ASYNCH'更轻量 - 避免
SELECT * FROM ... WHERE ROWNUM <= N配合无索引字段排序:触发大量临时段读写 → 频繁write系统调用 - PL/SQL批量操作不用
FORALL而用循环+单条DML:每条语句都经历完整解析/执行/提交路径 → syscall次数线性增长 - 监听器配置中
DISPATCHERS数远超CPU核心数:每个dispatcher进程都独立调度,空闲时也占调度队列
真正难处理的是那些无法从ASH直接归因的切换——比如SGA内存页被OS swap out后,Oracle访问时触发缺页中断,这属于内存子系统与调度器的联合行为,得结合/proc/<pid>/status里的MMU指标和vmstat的si/so列交叉验证。


















