Oracle 数据库服务器 CPU 突然升高时,最有效的方法之一,是先从操作系统找到真正占 CPU 的 Oracle 进程,再通过 V$PROCESS 和 V$SESSION 映射到具体数据库会话。
直接寻找高 CPU 的 Oracle 进程 PID。
1. 在 Linux 找到高 CPU Oracle 进程
可以先使用:
top
按:
P
按照 CPU 使用率排序。
也可以直接执行:
ps -eo pid,ppid,user,pcpu,pmem,etime,args \
--sort=-pcpu | head -20
针对 Oracle 用户:
ps -u oracle \
-o pid,ppid,pcpu,pmem,etime,args \
--sort=-pcpu | head -20
例如:
PID %CPU COMMAND
2367898.5 oracleORCL (LOCAL=NO)
1821112.3 ora_lgwr_ORCL
181925.6 ora_dbw0_ORCL
这里首先要区分两种情况:
oracleORCL (LOCAL=NO)
通常是前台 server process,可以继续映射到 Session 和 SQL。
而:
ora_lgwr_ORCL
ora_dbw0_ORCL
ora_ckpt_ORCL
属于后台进程,应从 redo、I/O、checkpoint 等方向继续分析,而不是寻找业务 SQL。Oracle 官方的进程架构文档也将服务器进程和后台进程作为不同角色分别描述。
2. 根据 OS PID 定位 Oracle Session
假设发现:
PID = 23678
执行:
SELECT
s.sid,
s.serial#,
s.username,
s.status,
s.sql_id,
s.event,
s.state,
s.seconds_in_wait,
p.spid,
s.machine,
s.program
FROM v$session s
JOIN v$process p
ON s.paddr = p.addr
WHERE p.spid ='23678';
例如返回:
SID 125
SERIAL# 4812
USERNAME TRADE
STATUS ACTIVE
SQL_ID 7abc123xyz890
EVENT ON CPU
SPID 23678
这时已经完成:
Linux PID
↓
Oracle Process
↓
Session
↓
SQL_ID
的完整映射。
3. 获取 SQL 和实际执行计划
拿到 SQL_ID 后查看 SQL:
SELECT
sql_id,
child_number,
plan_hash_value,
executions,
buffer_gets,
disk_reads,
cpu_time /1000000AS cpu_sec,
elapsed_time /1000000AS elapsed_sec,
sql_text
FROM v$sql
WHERE sql_id ='7abc123xyz890';
查看执行计划:
SELECT*
FROMTABLE(
dbms_xplan.display_cursor(
'7abc123xyz890',
NULL,
'ALLSTATS LAST'
)
);
重点关注:
A-Rows
Buffers
Reads
Starts
例如:
E-Rows=10
A-Rows=5000000
通常说明优化器估算严重偏差,可以进一步检查:
- 统计信息是否过期;
- 是否存在数据倾斜;
- Bind Peeking;
- 执行计划发生变化;
- 索引选择错误。
4. 如果高 CPU 的是 Oracle 后台进程
不能看到 Oracle PID CPU 高,就全部按 SQL 问题处理。
例如:
ora_lgwr_ORCL
CPU 或系统调用异常时,可以检查:
SELECT
event,
total_waits,
time_waited_micro /1000000AS time_waited_sec
FROM v$system_event
WHERE event LIKE'log file%';
如果是:
ora_dbw0_ORCL
可以重点观察:
SELECT
event,
total_waits,
time_waited_micro /1000000AS time_waited_sec
FROM v$system_event
WHERE event LIKE'db file parallel write%'
OR event LIKE'free buffer waits%';
因此完整判断流程应该是:
CPU 高
│
├─ 前台 oracleORCL (LOCAL=NO)
│ ↓
│ V$PROCESS → V$SESSION → SQL_ID
│
└─ 后台 ora_xxxx_ORCL
↓
根据后台进程职责分析
LGWR → redo
DBWR → datafile I/O
ARCn → archive
LMS → RAC Cache Fusion