先确认cpu飙升是否由数据库进程引起,再用gv$session定位rac中高cpu实例的活跃会话,结合sql_id查当前执行计划与绑定变量,并检查gc争用等rac特有等待事件。
查清cpu飙升是否真由数据库引起
别急着进oracle查sql,先确认是不是数据库进程在吃cpu。rac里节点间资源隔离弱,宿主机上其他进程(比如备份脚本、监控agent、内核线程)也可能拉高%us或%sy。用top -h看线程级占用,再结合ps -eo pid,ppid,comm,%cpu --sort=-%cpu | head -20定位高cpu的pid,然后cat /proc/<pid>/cmdline</pid>看实际命令。如果pid属于ora_<xxx>_<inst></inst></xxx>,才进入数据库层排查。
快速定位RAC中哪个实例的会话在耗CPU
RAC多实例共享同一套AWR/ASH数据,但v$session和v$process只反映当前连接实例的视图。直接查v$session可能漏掉其他节点的活跃会话。必须用gv$session,并带上inst_id字段:
SELECT inst_id, sid, serial#, username, program, sql_id, event, state, cpu_time/1000000 cpu_sec FROM gv$session WHERE status = 'ACTIVE' AND cpu_time > 10000000 ORDER BY cpu_time DESC;注意
cpu_time单位是微秒,>10秒才值得盯。同时检查program列——如果是oracle@node2 (J000),说明是Job进程,不是用户SQL;如果是sqlplus@node1,才要继续追SQL。从SQL_ID反查执行计划与绑定变量
拿到高CPU的sql_id后,别只看v$sql里的cpu_time累计值,那可能是历史总和。重点看当前是否还在跑:
SELECT inst_id, sql_id, child_number, plan_hash_value, executions, elapsed_time/1000000 elap_sec, cpu_time/1000000 cpu_sec FROM gv$sql WHERE sql_id = '<your_sql_id>' AND cpu_time > 0;</your_sql_id>如果
executions为0但cpu_sec持续涨,大概率是硬解析卡住(比如大量相似SQL未绑定变量)。此时查gv$sql_shared_cursor看UNBOUND_CURSOR或OPTIMIZER_MISMATCH是否为Y。另外,用DBMS_XPLAN.DISPLAY_CURSOR('<sql_id>', NULL, 'ALLSTATS LAST')</sql_id>看真实执行时的A-Rows和Buffers,比EXPLAIN PLAN准得多。注意RAC特有的争用陷阱
CPU飙升常是争用的结果,而非原因。比如gc cr block busy等待高,说明跨节点读一致性块频繁,触发大量CPU用于LMS进程协调;又或者enq: TX - row lock contention导致会话在本地反复重试获取锁,消耗CPU。查gv$system_event时务必加inst_id分组:
SELECT inst_id, event, total_waits, time_waited/100 time_sec FROM gv$system_event WHERE wait_class != 'Idle' AND time_waited > 100000 ORDER BY time_waited DESC;如果发现某实例
time_sec远高于其他节点,且等待集中在GC类事件,就要检查该实例上的热点对象是否缺少分区或局部索引,避免跨节点访问。最麻烦的情况是SQL本身没问题,但RAC的Cache Fusion机制在特定负载下引发LMS进程自旋——这时top里看到多个ora_lms0_<inst></inst>线程占满CPU,而gv$session里却看不到对应SQL。这种得立刻抓oradebug setmypid; oradebug dump systemstate 266,不然等不到AWR快照就错过了现场。











