1. CPU 分析概述
CPU作为数据库系统的核心计算资源,其使用效率直接影响着Oracle数据库的整体性能表现。AWR(Automatic Workload Repository)报告提供了全方位的CPU使用情况分析视角,能够帮助我们快速定位以下关键问题:
- 资源瓶颈识别:判断CPU是否成为当前系统的性能瓶颈
- 消耗分布分析:明确CPU时间主要消耗在哪些数据库操作上
- SQL定位:找出消耗CPU资源最多的SQL语句
- 争用检测:发现CPU资源竞争情况(如运行队列等待)
在实际生产环境中,我经常遇到这样的场景:DBA收到CPU使用率高的告警后,第一反应往往是"加CPU核心",但这可能只是治标不治本。通过AWR的CPU分析,我们能够深入理解CPU消耗的本质原因,从而采取针对性的优化措施。
经验分享:在分析CPU问题时,一定要区分"CPU真的不够用"和"CPU被低效使用"两种情况。前者需要扩容硬件,后者则需要优化SQL和参数配置。
2. Load Profile —— CPU 整体概览
2.1 关键指标解析
Load Profile部分提供了数据库CPU使用的宏观视图,以下是需要重点关注的指标:
| 指标 | 含义解释 | 单位 |
|---|---|---|
| DB Time | 所有数据库会话消耗的时间总和(包含CPU时间和等待时间) | 秒/秒 |
| DB CPU | 所有数据库会话消耗的纯CPU时间 | 秒/秒 |
| Background CPU Time | 后台进程(如DBWR、LGWR等)消耗的CPU时间 | 秒/秒 |
| Host CPU (CPUs) | 主机可用的CPU核心数量 | 个 |
| %User Time | CPU在用户态运行的时间占比(主要是应用和Oracle代码) | % |
| %System Time | CPU在内核态运行的时间占比(系统调用、中断处理等) | % |
| %WIO Time | CPU等待I/O完成的时间占比(此时CPU实际空闲) | % |
| %Idle Time | CPU完全空闲的时间占比 | % |
2.2 CPU使用率计算方法
sql复制-- 总CPU使用率计算
总CPU使用率 = %User Time + %System Time
CPU繁忙度 = 100% - %Idle Time
-- 数据库CPU占总CPU比例计算
DB CPU占比 = DB CPU / (Host CPU核心数 × 快照间隔时间)
2.3 性能判断标准
DB Time与DB CPU关系分析
| 现象 | 性能含义 | 优化建议 |
|---|---|---|
| DB CPU ≈ DB Time | CPU密集型负载,几乎没有等待事件 | 优化高CPU SQL,降低并行度 |
| DB CPU < 50% DB Time | 存在大量非CPU等待(I/O、锁、网络等) | 分析等待事件,针对性优化 |
| DB CPU > DB Time | 数据异常,这种情况理论上不可能发生 | 检查AWR报告完整性 |
主机CPU使用率评估
| CPU使用率范围 | 系统状态 | 处理建议 |
|---|---|---|
| < 70% | 正常 | 无需特别处理,持续监控即可 |
| 70~85% | 关注 | 开始优化高CPU SQL,检查是否有优化空间 |
| 85~95% | 警告 | 立即进行优化,考虑扩容规划 |
| > 95% | 危险 | CPU资源饱和,性能严重下降,需紧急处理 |
在实际运维中,我发现一个有用的经验法则:当DB CPU超过DB Time的70%,且主机CPU使用率持续高于80%时,就表明系统确实存在CPU资源不足的问题,需要考虑优化或扩容。
3. Time Model Statistics —— CPU 时间分布
3.1 关键统计项详解
Time Model统计提供了数据库时间消耗的详细分类,帮助我们理解CPU时间具体花在了哪些操作上:
| 统计项 | 详细说明 |
|---|---|
| DB Time | 所有前台会话消耗的总时间(包含CPU时间和等待时间) |
| DB CPU | 所有前台会话消耗的纯CPU时间 |
| background cpu time | 后台进程消耗的CPU时间 |
| sql execute elapsed time | SQL语句执行消耗的总时间 |
| parse time elapsed | SQL解析消耗的总时间(包含硬解析和软解析) |
| hard parse elapsed time | 硬解析消耗的时间(需要重新生成执行计划) |
| PL/SQL execution elapsed time | PL/SQL代码执行消耗的时间 |
| connection management call elapsed time | 连接建立和断开等管理操作消耗的时间 |
3.2 分析SQL示例
sql复制-- 查看Time Model统计详情
SELECT STAT_NAME,
ROUND(VALUE / 1000000, 2) AS TIME_SEC,
ROUND(VALUE / 1000000 /
(SELECT VALUE / 1000000 FROM V$SYS_TIME_MODEL
WHERE STAT_NAME = 'DB time') * 100, 2) AS PCT_DB_TIME
FROM V$SYS_TIME_MODEL
WHERE STAT_NAME IN (
'DB time',
'DB CPU',
'background cpu time',
'sql execute elapsed time',
'parse time elapsed',
'hard parse elapsed time',
'PL/SQL execution elapsed time',
'connection management call elapsed time'
)
ORDER BY VALUE DESC;
3.3 常见问题诊断与优化
根据Time Model统计,我们可以快速识别以下典型问题:
| 异常现象 | 可能原因 | 优化方向 |
|---|---|---|
| hard parse time占比 > 10% | 硬解析过多,未使用绑定变量 | 应用改用绑定变量;增大shared_pool_size |
| parse time占比 > 20% | 解析开销过大(软解析也多) | 使用连接池减少连接创建;优化重复解析的SQL |
| PL/SQL time占比 > 50% | 业务逻辑大量使用PL/SQL | 优化PL/SQL代码;减少循环次数;考虑改用原生SQL |
| connection mgmt time占比高 | 频繁建立/断开连接 | 实现连接池;调整应用连接管理策略 |
实战经验:我曾遇到一个系统,hard parse time占比高达35%。通过强制使用绑定变量和调整shared_pool_size后,CPU使用率直接下降了40%。这展示了正确解析Time Model数据的重要性。
4. Operating System Statistics —— 操作系统 CPU
4.1 关键操作系统指标
操作系统层面的CPU统计提供了硬件资源使用的真实情况:
| 指标 | 详细说明 |
|---|---|
| NUM_CPUS | 逻辑CPU核心总数(含超线程) |
| NUM_CPU_CORES | 物理CPU核心数 |
| NUM_CPU_SOCKETS | CPU插槽数量 |
| LOAD | 系统1分钟平均负载 |
| BUSY_TIME | CPU繁忙时间(单位:百分之一秒) |
| IDLE_TIME | CPU空闲时间 |
| USER_TIME | 用户态CPU时间 |
| SYS_TIME | 内核态CPU时间 |
| IOWAIT_TIME | CPU等待I/O的时间 |
| RSRC_MGR_CPU_WAIT_TIME | 因资源管理器限制导致的CPU等待时间 |
4.2 分析SQL示例
sql复制-- 查看操作系统CPU统计
SELECT STAT_NAME, VALUE, COMMENTS
FROM V$OSSTAT
WHERE STAT_NAME IN (
'NUM_CPUS',
'NUM_CPU_CORES',
'NUM_CPU_SOCKETS',
'LOAD',
'BUSY_TIME',
'IDLE_TIME',
'USER_TIME',
'SYS_TIME',
'IOWAIT_TIME',
'RSRC_MGR_CPU_WAIT_TIME'
)
ORDER BY STAT_NAME;
-- 计算详细CPU使用率
SELECT
ROUND((1 - idle.value / busy.value) * 100, 2) AS CPU_USAGE_PCT,
ROUND(user.value / busy.value * 100, 2) AS USER_PCT,
ROUND(sys.value / busy.value * 100, 2) AS SYS_PCT,
ROUND(iowait.value / busy.value * 100, 2) AS IOWAIT_PCT
FROM
(SELECT VALUE FROM V$OSSTAT WHERE STAT_NAME = 'BUSY_TIME') busy,
(SELECT VALUE FROM V$OSSTAT WHERE STAT_NAME = 'IDLE_TIME') idle,
(SELECT VALUE FROM V$OSSTAT WHERE STAT_NAME = 'USER_TIME') user,
(SELECT VALUE FROM V$OSSTAT WHERE STAT_NAME = 'SYS_TIME') sys,
(SELECT VALUE FROM V$OSSTAT WHERE STAT_NAME = 'IOWAIT_TIME') iowait;
4.3 系统负载(LOAD)解读
系统负载(LOAD)是判断CPU压力的重要指标,其解读规则如下:
code复制LOAD值判断标准:
LOAD < CPU核心数 → 系统正常,CPU资源充足
LOAD = CPU核心数 → CPU刚好饱和,无闲置资源
LOAD > CPU核心数 → CPU过载,存在等待队列
实际案例:
16核CPU,LOAD=12 → 正常使用(约75%利用率)
16核CPU,LOAD=20 → 过载(125%利用率,有4个进程在排队)
在分析LOAD时,需要特别注意短期高峰和持续高负载的区别。偶尔的LOAD高峰可能不会导致严重问题,但如果LOAD持续高于CPU核心数的1.5倍,就需要立即介入调查。
5. Top 10 Foreground Events —— CPU 相关等待
5.1 CPU相关等待事件详解
虽然CPU本身不是等待事件,但某些等待事件与CPU资源争用密切相关:
| 等待事件 | 详细说明 | 常见原因 |
|---|---|---|
| latch: shared pool | 共享池闩锁争用 | 硬解析过多;shared_pool碎片化 |
| latch: cache buffers chains | Buffer Cache哈希链闩锁争用 | 热块竞争;索引根块争用 |
| latch: library cache | 库缓存闩锁争用 | 硬解析过多;SQL版本过多 |
| cursor: pin S wait on X | 游标固定等待 | 并发执行同一SQL且版本不一致 |
| cursor: mutex X | 游标互斥锁等待 | 高并发执行同一SQL |
| enq: TX - row lock contention | 行锁等待 | 并发更新同一行数据 |
| resmgr: cpu quantum | 资源管理器CPU限制 | 启用了资源管理器且CPU配额用完 |
5.2 分析SQL示例
sql复制-- 查看CPU相关等待事件统计
SELECT EVENT,
TOTAL_WAITS,
ROUND(TIME_WAITED / 100, 2) AS TIME_WAITED_SEC,
ROUND(AVERAGE_WAIT * 10, 2) AS AVG_WAIT_MS
FROM V$SYSTEM_EVENT
WHERE EVENT IN (
'latch: shared pool',
'latch: cache buffers chains',
'latch: library cache',
'cursor: pin S wait on X',
'cursor: mutex X',
'enq: TX - row lock contention',
'resmgr: cpu quantum'
)
ORDER BY TIME_WAITED DESC;
-- 查看当前持有闩锁的会话
SELECT l.NAME AS LATCH_NAME,
s.SID,
s.SERIAL#,
s.USERNAME,
s.PROGRAM,
s.SQL_ID,
s.EVENT,
s.SECONDS_IN_WAIT
FROM V$LATCHHOLDER lh
JOIN V$LATCH l ON lh.LADDR = l.ADDR
JOIN V$SESSION s ON lh.SID = s.SID
ORDER BY s.SECONDS_IN_WAIT DESC;
避坑指南:当看到latch: cache buffers chains等待时,不要立即增大buffer cache。正确的做法是先找出热块对应的表和索引,通过调整SQL或索引设计来减少热块争用。
6. SQL ordered by CPU Time —— 高 CPU SQL
6.1 AWR报告中的高CPU SQL
AWR报告会列出消耗CPU最多的SQL语句,格式通常如下:
code复制SQL ordered by CPU Time (DB/Inst: ORCL/orcl1 Snaps: 100-101)
-> Total CPU Time: 12,345 seconds
-> Captured SQL account for 87.5% of Total
CPU Time Executions CPU per %Total Elapsed Time Physical Reads
(s) Exec (s) (s)
-------- ---------- -------- ------ ------------ --------------
4567.8 1234 3.7 37.0 5678.9 123456 SQL_ID: abc123
2345.6 567 4.1 19.0 3456.7 67890 SQL_ID: def456
6.2 分析SQL示例
sql复制-- 实时查看高CPU消耗SQL
SELECT SQL_ID,
EXECUTIONS,
ROUND(CPU_TIME / 1000000, 2) AS CPU_TIME_SEC,
ROUND(CPU_TIME / 1000000 / DECODE(EXECUTIONS, 0, 1, EXECUTIONS), 4) AS CPU_PER_EXEC_SEC,
ROUND(ELAPSED_TIME / 1000000, 2) AS ELAPSED_TIME_SEC,
ROUND(CPU_TIME / DECODE(ELAPSED_TIME, 0, 1, ELAPSED_TIME) * 100, 2) AS CPU_PCT,
DISK_READS,
BUFFER_GETS,
SUBSTR(SQL_TEXT, 1, 100) AS SQL_TEXT
FROM V$SQLSTATS
WHERE CPU_TIME > 10000000 -- 只查看CPU消耗大于10秒的SQL
ORDER BY CPU_TIME DESC
FETCH FIRST 20 ROWS ONLY;
-- 查看SQL执行计划
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('abc123', NULL, 'ALLSTATS LAST'));
-- 查询AWR历史中的高CPU SQL
SELECT s.SQL_ID,
SUM(s.CPU_TIME_DELTA) / 1000000 AS TOTAL_CPU_SEC,
SUM(s.EXECUTIONS_DELTA) AS TOTAL_EXECS,
ROUND(SUM(s.CPU_TIME_DELTA) / 1000000 /
DECODE(SUM(s.EXECUTIONS_DELTA), 0, 1, SUM(s.EXECUTIONS_DELTA)), 4) AS CPU_PER_EXEC_SEC
FROM DBA_HIST_SQLSTAT s
WHERE s.SNAP_ID BETWEEN :begin_snap AND :end_snap
GROUP BY s.SQL_ID
ORDER BY TOTAL_CPU_SEC DESC
FETCH FIRST 20 ROWS ONLY;
6.3 高CPU SQL优化策略
针对不同特征的高CPU SQL,可采取以下优化方法:
| SQL特征 | 优化方案 |
|---|---|
| 全表扫描大表 | 添加合适的索引;考虑分区表策略 |
| 嵌套循环连接大表 | 改用Hash Join或Merge Join;确保驱动表足够小 |
| 大量函数调用 | 减少自定义函数调用;改用SQL原生操作 |
| 复杂正则表达式 | 简化正则模式;考虑改用LIKE |
| 大量排序操作 | 添加合适的索引避免排序;增大PGA_AGGREGATE_TARGET |
| 笛卡尔积 | 检查并补充缺失的JOIN条件 |
| 并行度过高 | 适当降低并行度(使用NO_PARALLEL或调整PARALLEL hint) |
在实际优化过程中,我发现一个有用的技巧:对于高CPU的SQL,先检查其执行计划中的"Buffers"列。如果逻辑读(Buffer Gets)异常高,通常意味着可以通过优化访问路径来减少CPU消耗。
7. Instance Activity Stats —— CPU 相关统计
7.1 关键实例活动统计
实例活动统计提供了更细粒度的CPU使用信息:
| 统计项 | 详细说明 |
|---|---|
| CPU used by this session | 当前会话消耗的CPU时间 |
| parse time cpu | SQL解析消耗的CPU时间 |
| recursive cpu usage | 递归SQL消耗的CPU时间(如数据字典查询) |
| session logical reads | 会话执行的逻辑读次数(Buffer Cache访问) |
| sorts (memory) | 在内存中完成的排序操作次数 |
| sorts (disk) | 溢出到磁盘的排序操作次数 |
7.2 分析SQL示例
sql复制-- 查看CPU相关实例统计
SELECT NAME, VALUE
FROM V$SYSSTAT
WHERE NAME IN (
'CPU used by this session',
'parse time cpu',
'recursive cpu usage',
'session logical reads',
'sorts (memory)',
'sorts (disk)'
)
ORDER BY NAME;
-- 计算排序溢出率
SELECT
mem.value AS SORTS_MEMORY,
disk.value AS SORTS_DISK,
ROUND(disk.value /
DECODE(mem.value + disk.value, 0, 1, mem.value + disk.value) * 100, 2) AS DISK_SORT_PCT
FROM
(SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'sorts (memory)') mem,
(SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'sorts (disk)') disk;
-- 排序溢出率判断标准
-- < 1%: 优秀
-- 1-5%: 可接受
-- > 5%: 需要增大PGA
8. Latch Statistics —— 闩锁争用
8.1 关键闩锁类型
闩锁(Latch)是Oracle内部的轻量级锁机制,用于保护内存结构:
| 闩锁名称 | 保护对象 | 争用原因 |
|---|---|---|
| shared pool | 共享池内存结构 | 硬解析过多;shared_pool碎片化 |
| library cache | 库缓存 | 硬解析过多;SQL版本过多 |
| cache buffers chains | Buffer Cache哈希链 | 热块竞争;索引根块争用 |
| cache buffers lru chain | Buffer Cache LRU链 | DBWR写入慢;脏块积压 |
| row cache objects | 数据字典缓存 | 频繁访问数据字典 |
| redo allocation | Redo日志分配缓冲区 | 高并发DML;LOG_BUFFER太小 |
| redo copy | Redo日志复制缓冲区 | 小事务过多;LOG_BUFFER太小 |
8.2 分析SQL示例
sql复制-- 查看闩锁争用统计
SELECT NAME,
GETS,
MISSES,
ROUND(MISSES / DECODE(GETS, 0, 1, GETS) * 100, 4) AS MISS_RATIO_PCT,
SLEEPS,
ROUND(SLEEPS / DECODE(MISSES, 0, 1, MISSES) * 100, 4) AS SLEEP_RATIO_PCT,
WAIT_TIME / 1000000 AS WAIT_TIME_SEC
FROM V$LATCH
WHERE GETS > 0
ORDER BY WAIT_TIME DESC
FETCH FIRST 20 ROWS ONLY;
-- 查看当前持有闩锁的会话
SELECT l.NAME AS LATCH_NAME,
s.SID,
s.SERIAL#,
s.USERNAME,
s.PROGRAM,
s.SQL_ID,
s.EVENT,
s.SECONDS_IN_WAIT
FROM V$LATCHHOLDER lh
JOIN V$LATCH l ON lh.LADDR = l.ADDR
JOIN V$SESSION s ON lh.SID = s.SID
ORDER BY s.SECONDS_IN_WAIT DESC;
8.3 闩锁优化方案
针对不同类型的闩锁争用,可采取以下优化措施:
| 闩锁争用类型 | 优化方案 |
|---|---|
| shared pool/library cache | 使用绑定变量;增大shared_pool_size;应用SQL标准化 |
| cache buffers chains | 优化热块访问;使用反向键索引;考虑哈希分区 |
| redo allocation/copy | 增大LOG_BUFFER;减少小事务提交频率;使用批量提交 |
| row cache objects | 增大shared_pool_size(包含数据字典缓存) |
9. Mutex Statistics —— 互斥锁争用
9.1 Mutex类型解析
Mutex(互斥锁)是Oracle 11g引入的轻量级锁机制,用于替代部分闩锁:
| Mutex类型 | 详细说明 |
|---|---|
| Cursor Mutex | 保护游标(SQL执行计划) |
| Library Cache Mutex | 保护库缓存对象 |
9.2 分析SQL示例
sql复制-- 查看Mutex统计信息
SELECT MUTEX_TYPE,
LOCATION,
GETS,
SLEEPS,
ROUND(SLEEPS / DECODE(GETS, 0, 1, GETS) * 100, 4) AS SLEEP_RATIO_PCT,
WAIT_TIME / 1000000 AS WAIT_TIME_SEC
FROM V$MUTEX_SLEEP
WHERE GETS > 0
ORDER BY WAIT_TIME DESC
FETCH FIRST 20 ROWS ONLY;
-- 查看当前Mutex等待会话
SELECT EVENT,
COUNT(*) AS SESSION_COUNT,
ROUND(AVG(WAIT_TIME_MICRO) / 1000, 2) AS AVG_WAIT_MS
FROM V$SESSION
WHERE EVENT LIKE '%mutex%'
GROUP BY EVENT
ORDER BY SESSION_COUNT DESC;
10. Shared Pool Statistics —— 共享池分析
10.1 共享池关键指标
共享池存储SQL执行计划、PL/SQL代码和数据字典缓存:
sql复制-- 查看共享池使用情况
SELECT POOL,
NAME,
ROUND(BYTES / 1024 / 1024, 2) AS SIZE_MB
FROM V$SGASTAT
WHERE POOL = 'shared pool'
ORDER BY BYTES DESC
FETCH FIRST 20 ROWS ONLY;
-- 评估共享池碎片化
SELECT
ROUND(SUM(DECODE(CHUNK_SIZE, NULL, 0, CHUNK_SIZE)) / 1024 / 1024, 2) AS FREE_MB,
COUNT(*) AS FREE_CHUNKS,
ROUND(AVG(CHUNK_SIZE) / 1024, 2) AS AVG_CHUNK_KB,
MAX(CHUNK_SIZE) / 1024 AS MAX_CHUNK_KB
FROM V$SHARED_POOL_RESERVED
WHERE FREE = 'YES';
-- 当AVG_CHUNK_KB < 100KB时,表明共享池碎片化严重
-- 检查库缓存命中率
SELECT NAMESPACE,
GETS,
GETHITS,
ROUND(GETHITS / DECODE(GETS, 0, 1, GETS) * 100, 2) AS HIT_RATIO_PCT,
PINS,
PINHITS,
ROUND(PINHITS / DECODE(PINS, 0, 1, PINS) * 100, 2) AS PIN_HIT_RATIO_PCT,
RELOADS,
INVALIDATIONS
FROM V$LIBRARYCACHE
ORDER BY NAMESPACE;
-- 理想情况下,HIT_RATIO_PCT应>95%
-- RELOADS高表示共享池不足,对象被换出后又重新加载
10.2 硬解析诊断
sql复制-- 查看解析统计
SELECT NAME, VALUE
FROM V$SYSSTAT
WHERE NAME IN (
'parse count (total)',
'parse count (hard)',
'parse count (failures)'
);
-- 计算硬解析率
SELECT
total.value AS TOTAL_PARSES,
hard.value AS HARD_PARSES,
ROUND(hard.value /
DECODE(total.value, 0, 1, total.value) * 100, 2) AS HARD_PARSE_PCT
FROM
(SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'parse count (total)') total,
(SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'parse count (hard)') hard;
-- 生产系统硬解析率应<5%
-- 查找未使用绑定变量的SQL
SELECT SQL_ID,
EXECUTIONS,
PARSE_CALLS,
ROUND(PARSE_CALLS / DECODE(EXECUTIONS, 0, 1, EXECUTIONS), 2) AS PARSE_PER_EXEC,
SUBSTR(SQL_TEXT, 1, 100) AS SQL_TEXT
FROM V$SQLSTATS
WHERE EXECUTIONS > 100
AND PARSE_CALLS / DECODE(EXECUTIONS, 0, 1, EXECUTIONS) > 0.8
ORDER BY PARSE_CALLS DESC
FETCH FIRST 20 ROWS ONLY;
-- PARSE_PER_EXEC接近1表示每次执行都重新解析,未使用绑定变量
11. Parallel Execution Statistics —— 并行执行
11.1 并行执行监控
sql复制-- 查看并行执行统计
SELECT NAME, VALUE
FROM V$SYSSTAT
WHERE NAME LIKE '%parallel%'
ORDER BY NAME;
-- 查看当前并行会话
SELECT s.SID,
s.SERIAL#,
s.USERNAME,
s.SQL_ID,
px.DEGREE AS PARALLEL_DEGREE,
px.REQ_DEGREE AS REQUESTED_DEGREE,
px.SERVER_SET AS SERVER_SET
FROM V$SESSION s
JOIN V$PX_SESSION px ON s.SID = px.SID
WHERE px.QCSID IS NOT NULL
ORDER BY px.DEGREE DESC;
-- 检查并行服务器使用情况
SELECT
(SELECT VALUE FROM V$PARAMETER WHERE NAME = 'parallel_max_servers') AS MAX_SERVERS,
(SELECT COUNT(*) FROM V$PX_PROCESS WHERE STATUS = 'IN USE') AS SERVERS_IN_USE,
(SELECT COUNT(*) FROM V$PX_PROCESS WHERE STATUS = 'AVAILABLE') AS SERVERS_AVAILABLE
FROM DUAL;
11.2 并行度优化建议
sql复制-- 识别高并行度SQL
SELECT SQL_ID,
EXECUTIONS,
PX_SERVERS_EXECUTIONS,
ROUND(PX_SERVERS_EXECUTIONS / DECODE(EXECUTIONS, 0, 1, EXECUTIONS), 0) AS AVG_PARALLEL_DEGREE,
ROUND(CPU_TIME / 1000000, 2) AS CPU_TIME_SEC,
SUBSTR(SQL_TEXT, 1, 100) AS SQL_TEXT
FROM V$SQLSTATS
WHERE PX_SERVERS_EXECUTIONS > 0
ORDER BY PX_SERVERS_EXECUTIONS DESC
FETCH FIRST 20 ROWS ONLY;
-- 调整并行度参数
ALTER SYSTEM SET PARALLEL_MAX_SERVERS = 64 SCOPE=BOTH;
ALTER SYSTEM SET PARALLEL_DEGREE_POLICY = AUTO SCOPE=BOTH; -- 启用自动并行度
ALTER SYSTEM SET PARALLEL_MIN_TIME_THRESHOLD = 10 SCOPE=BOTH; -- 只对预计执行>10秒的SQL启用并行
12. CPU 优化方向汇总
12.1 高CPU问题诊断矩阵
| 现象 | 可能原因 | 优化方案 |
|---|---|---|
| DB CPU ≈ DB Time | CPU密集型负载 | 优化高CPU SQL;降低并行度 |
| 硬解析率 > 5% | 未使用绑定变量 | 应用改用绑定变量;增大shared_pool_size |
| 闩锁争用严重 | 热块竞争/硬解析 | 优化热块访问;使用绑定变量 |
| 排序溢出率 > 5% | PGA内存不足 | 增大pga_aggregate_target |
| 并行度过高 | 并行查询过多 | 降低并行度;限制并行服务器数 |
| %System Time高 | 内核态CPU消耗大 | 检查系统调用;可能是网络/磁盘驱动问题 |
12.2 参数调整参考
sql复制-- 共享池调整(减少硬解析)
ALTER SYSTEM SET SHARED_POOL_SIZE = 4G SCOPE=BOTH;
-- PGA调整(减少排序溢出)
ALTER SYSTEM SET PGA_AGGREGATE_TARGET = 4G SCOPE=BOTH;
-- 并行度控制
ALTER SYSTEM SET PARALLEL_MAX_SERVERS = 32 SCOPE=BOTH;
ALTER SYSTEM SET PARALLEL_DEGREE_LIMIT = 8 SCOPE=BOTH;
-- 强制游标共享(慎用)
ALTER SYSTEM SET CURSOR_SHARING = FORCE SCOPE=BOTH;
-- 注意:FORCE可能导致执行计划不优,建议优先修改应用代码
-- 增大LOG_BUFFER(减少redo闩锁争用)
ALTER SYSTEM SET LOG_BUFFER = 32M SCOPE=SPFILE;
-- 需重启数据库生效
13. CPU 分析快速诊断流程
sql复制1. 检查Load Profile
→ 比较DB CPU与DB Time比例,判断负载类型
→ 查看主机CPU使用率,评估资源饱和度
2. 分析Time Model Statistics
→ 检查hard parse time占比,识别绑定变量问题
→ 评估PL/SQL time占比,判断代码优化空间
3. 查看Operating System Statistics
→ 确认LOAD是否超过CPU核心数
→ 检查%System Time是否异常高(>20%)
4. 定位高CPU SQL
→ 找出Top 10 CPU消耗SQL
→ 分析执行计划,优化访问路径
5. 检查Latch Statistics
→ 识别shared pool/library cache争用
→ 发现cache buffers chains热块问题
6. 评估Shared Pool状态
→ 确认硬解析率是否超标(>5%)
→ 检查库缓存命中率(应>95%)
7. 监控Parallel Execution
→ 判断并行度是否合理
→ 检查并行服务器资源使用情况
通过这套系统的CPU分析方法,我成功帮助多个客户解决了CPU性能瓶颈问题。记住,有效的CPU优化不在于盲目增加硬件资源,而在于深入理解工作负载特征,采取精准的优化措施。