Oracle数据库的性能问题,十有六七能追溯到内存配置上。缓冲区命中率跌破90%、共享池频繁报ORA-04031、排序大量消耗临时表空间,这些现象背后都是SGA或PGA的分配出了问题。要想把内存参数调对,首先得弄清楚Oracle内存结构的组成,以及各组件分别承担什么职责,然后再结合业务负载特点去分配资源。

Oracle内存结构的整体构成
Oracle实例的内存分为两大部分:SGA(System Global Area,系统全局区)和PGA(Program Global Area,程序全局区)。SGA在实例启动时分配,是所有后台进程和服务进程共享的一块内存区域;PGA则是每个服务进程独享的私有内存,进程创建时分配,进程终止时释放。
在传统手工管理模式下,DBA需要分别设置SHARED_POOL_SIZE、DB_CACHE_SIZE、LOG_BUFFER等参数,管理起来相当繁琐。从10g开始,Oracle引入了自动共享内存管理(ASMM),只需要设置SGA_TARGET和SGA_MAX_SIZE,数据库会根据负载自动在各个组件之间调配内存。11g之后又推出了自动内存管理(AMM),通过MEMORY_TARGET参数把SGA和PGA统一纳管。不过在生产环境中,AMM依赖的HugePage配合并不好,很多DBA更倾向于关闭AMM、只启用ASMM加PGA自动管理,这样既有自动化带来的便利,又能保留对大页内存的支持。
SGA各组件的职责与优化要点
SGA中最核心的三个组件是数据库缓冲区高速缓存、共享池和日志缓冲区。数据库缓冲区缓存存放从数据文件读入的数据块,它的命中率直接决定了物理读的多少。共享池负责缓存SQL语句的解析结果、执行计划以及数据字典信息,游标共享、硬解析问题都发生在这里。日志缓冲区则是事务修改的暂存区,写入很快就会被LGWR刷到联机日志文件,通常几MB到几十MB就够用了,设置过大反而没有意义。
查看各组件当前占用情况的常用查询如下:
SELECT component, ROUND(current_size/1024/1024) AS size_mb
FROM v$sga_dynamic_components
ORDER BY current_size DESC;
-- 查看缓冲区命中率
SELECT NAME, VALUE
FROM v$sysstat
WHERE NAME IN ('db block gets','consistent gets','physical reads');
命中率计算公式为1减去physical reads除以db block gets与consistent gets之和,一般要求保持在95%以上。如果命中率明显偏低,同时缓冲区默认池的占用已经接近DB_CACHE_SIZE上限,就应该考虑增加缓冲区缓存的配额。而对于共享池,重点观察v$librarycache中的reloads与pins比率,如果硬解析比例高,除了加大共享池,还要检查应用端是否使用了绑定变量,单纯扩容只是治标不治本。
使用ASMM时需要留意一个细节:如果设置了SHARED_POOL_SIZE或DB_CACHE_SIZE的值,这些值会被当作下限而非精确值,数据库仍会在该底线之上自动调整。排查ORA-04031错误时,可以先查询v$sgastat确认共享池中哪类对象占用过大,常见的是SQL AREA过多,此时清理共享池或重启应用释放游标往往比直接加大参数更有效。
PGA的配置与排序性能优化
PGA中包含排序区、哈希区、会话内存等区域,主要服务于排序、哈希连接、位图运算等操作。从9i开始通过PGA_AGGREGATE_TARGET参数实现自动PGA管理,数据库以该值为全局目标,在各活动进程间动态分配。设置为0则回到传统的SORT_AREA_SIZE手工模式,现在已经很少有人这么做了。
评估PGA是否够用,最直接的视图是v$pgastat,重点看两个指标:workarea executions为optimal的比例,以及cache hit percentage。排序操作全部在内存中完成即为optimal执行,若需要一趟落盘则是1-pass,多趟落盘则是multi-pass。
SELECT * FROM v$pgastat WHERE name IN (
'aggregate PGA target parameter',
'total PGA allocated',
'cache hit percentage',
'over allocation count'
);
-- 查看工作区执行情况
SELECT low_optimal_size/1024 AS low_kb,
executions_optimal, executions_1pass, executions_multipass
FROM v$sql_workarea_histogram
WHERE executions_multipass > 0;
如果multi-pass执行频繁出现,说明排序工作区不足,数据被反复写入临时表盘再读回,性能会急剧下降。这时适当调大PGA_AGGREGATE_TARGET即可。反过来,如果total PGA allocated长期远低于目标值,说明PGA配置偏大,内存被闲置浪费,可以压缩配额挪给SGA。over allocation count若持续增长,则代表设置的目标值太小,Oracle被迫超配,也需要加大参数。一个经验性的起始值是物理内存的20%左右,再根据报表类、OLTP类业务比重微调:分析型查询多的库可以放宽到30%甚至更高。
SGA与PGA的平衡及实战调整步骤
SGA和PGA共享同一台服务器的物理内存,此消彼长。OLTP系统以频繁的小事务为主,缓冲区命中率是生命线,内存应该向SGA倾斜,常见比例是SGA占80%、PGA占20%。数据仓库或报表系统存在大量排序与哈希操作,PGA需要更多配额,六四开甚至五五开都不罕见。此外还必须预留操作系统自身开销和Oracle进程的栈内存,不要把物理内存占满,否则一旦触发swap,性能会断崖式下跌。
实际调优时建议按以下步骤推进:先用AWR报告观察Instance Efficiency和PGA相关的统计;再通过v$sga_target_advice和v$pga_target_advice查看数据库给出的建议值,这两张视图会模拟不同参数尺寸下的命中率变化,非常有参考价值。
SELECT pga_target_for_estimate/1024/1024 AS pga_mb,
estd_extra_bytes_rw/1024/1024 AS extra_rw_mb,
estd_overalloc_count
FROM v$pga_target_advice;
SELECT sga_size/1024 AS sga_mb, estd_physical_reads
FROM v$sga_target_advice
ORDER BY sga_size;
找到物理读或额外读写显著下降的拐点作为新参数值,避免盲目堆内存带来的边际收益递减。修改参数时优先使用scope=both的ALTER SYSTEM语句在线生效,同时更新spfile。最后还有一点容易被忽略:Linux上部署大型SGA时务必配置HugePage,并设置USE_LARGE_PAGES=TRUE,这不仅能减轻页表对内存的额外消耗,还能避免AMM带来的地址空间问题,属于大内存实例的标配做法。
内存优化没有一次到位的万能参数,业务负载变了,最优配置也会跟着变。建立基线、定期回顾AWR趋势、结合advice视图小步调整,才是让SGA与PGA持续匹配业务节奏的正确姿势。
Oracle SGAPGA配置优化内存结构修改时间:2026-09-10 15:06:42