共享池是Oracle SGA中最容易出问题的区域之一,它既要缓存SQL语句的执行计划,又要存放数据字典信息,还要为PL/SQL对象分配内存。一旦配置不当,轻则引发大量的硬解析消耗CPU,重则抛出ORA-04031错误导致业务中断。这篇文章围绕共享池的调整展开,先讲清楚它的内部结构,再给出判断依据和具体的调整手段。

一、先弄清楚共享池里面装了什么
共享池主要由三大块组成:library cache(库缓存)、dictionary cache(数据字典缓存)以及一大块碎片化程度较高的空闲区域。其中library cache存放的是SQL语句、执行计划、PL/SQL对象和锁信息,是DBA最需要关注的部分;dictionary cache则缓存表结构、列定义、用户权限等元数据,它的命中率直接影响解析速度。
从Oracle 9i开始,SGA可以通过SGA_TARGET自动管理,共享池的大小由MMAN进程根据负载动态分配。但自动管理并非万能,当某个版本出现bug或者业务特征特殊时,手动指定SHARED_POOL_SIZE仍然是最直接的控制手段。需要注意的是,如果同时设置了SGA_TARGET和SHARED_POOL_SIZE,后者会被当作共享池的下限值,这是一个常见的认知误区。
共享池内部的分配以chunk为单位,小于等于4400字节的请求从小的空闲链表分配,大于4400字节的则走保留区域。保留区域默认为共享池的5%,最小值是5000KB左右,可以通过参数SHARED_POOL_RESERVED_SIZE调整。理解这一点很重要,因为ORA-04031错误往往就是大块内存找不到连续chunk导致的。
二、如何判断共享池是否需要调整
调优不能凭感觉,得拿数据说话。最基础的判断指标是库缓存命中率,查询v$librarycache视图可以看到pin和reload的统计信息:
SELECT namespace, pins, pinhits, reloads, invalidations
FROM v$librarycache
WHERE namespace IN ('SQL AREA', 'TABLE/PROCEDURE', 'BODY');
-- 命中率的粗略计算方式
SELECT SUM(pinhits) / SUM(pins) * 100 AS hit_ratio
FROM v$librarycache;
一般认为命中率低于95%就需要警惕了,reloads持续增长说明缓存的执行计划被频繁淘汰重载,通常意味着共享池偏小,或者应用存在大量不带绑定变量的SQL。除了命中率,还要观察v$sgastat中shared pool各子池的占用情况:
SELECT name, bytes / 1024 / 1024 AS size_mb FROM v$sgastat WHERE pool = 'shared pool' ORDER BY bytes DESC;
Oracle 10g以后提供了v$shared_pool_advice视图,它模拟了共享池在不同大小下的解析时间预估,是判断是否需要扩容的利器:
SELECT shared_pool_size_mb, estd_lc_size_mb,
estd_lc_time_saved_factor
FROM v$shared_pool_advice;
如果ESTD_LC_TIME_SAVED_FACTOR在当前大小附近已经趋近1的平稳区间,说明继续加内存收益不大,此时问题多半出在SQL本身而不是内存容量。相反,如果该因子随共享池增大还在明显上升,说明扩容是有意义的。
三、具体的调整建议与实战手段
第一类手段是参数层面的调整。如果确定共享池不足,直接增大SHARED_POOL_SIZE,建议每次调整幅度在20%到30%之间,调整后持续观察命中率变化,避免一次性加太大造成内存浪费。同时配合调整SHARED_POOL_RESERVED_SIZE,让偶发的大对象分配有回旋余地,一般设为共享池的10%左右即可。
第二类手段是使用DBMS_SHARED_POOL包把频繁使用的大对象固定在内存中。对于体积较大的PL/SQL包或者经常被刷出的热点对象,KEEP操作可以有效减少reload:
-- 先安装该包(如未安装),脚本位于 rdbms/admin/dbmspool.sql
-- 将对象keep到共享池
EXEC DBMS_SHARED_POOL.KEEP('PKG_BIZ_CORE', 'P');
-- 查看已经被keep的对象
SELECT * FROM v$db_object_cache WHERE kept = 'YES';
需要注意的是,KEEP的对象在数据库重启后会失效,需要在启动后重新执行,通常会把KEEP语句写进开机脚本或者用数据库触发器实现。另外KEEP只是减少被淘汰的概率,并不能替代绑定变量的改造。
第三类也是最重要的手段:治理硬解析。硬解析是共享池压力的最大来源,可以通过以下查询找出没有使用绑定变量的SQL:
SELECT substr(sql_text, 1, 60) AS sql_fragment,
count(*) AS copies
FROM v$sqlarea
GROUP BY substr(sql_text, 1, 60)
HAVING count(*) > 10
ORDER BY copies DESC;
同一条语句出现大量copies,基本可以断定应用端拼接了字面值。推动开发改造成绑定变量,或者开启CURSOR_SHARING=FORCE(这是不得已的兜底方案,可能带来执行计划选择异常的副作用),才能从根源上解决问题。同时关注SESSION_CACHED_CURSORS和OPEN_CURSORS的配置,减少会话级的光标开销。
四、遇到ORA-04031时的应急处理
ORA-04031意味着共享池无法分配到足够大的连续内存。出现这个错误时不要急着重启实例,可以先查看alert日志确认报错时请求的内存大小。如果请求的是大块内存,优先考虑增大保留区域;如果请求的是小块内存且伴随大量碎片,往往是不合理的SQL模式导致的,重启只能治标,过几天问题会卷土重来。
排查时可以借助v$shared_pool_reserved视图,如果REQUEST_FAILURES持续增加而LAST_FAILURE_SIZE大于SHARED_POOL_RESERVED_MIN_ALLOC,说明保留区域确实不够用。此外,定期flush共享池(ALTER SYSTEM FLUSH SHARED_POOL)并不是推荐的做法,它会瞬间产生大量硬解析,反而冲击CPU,只有在确认内存严重碎片化时才作为临时手段使用。
总结来说,共享池调优的思路应该是:先通过视图量化现状,区分是容量不足还是SQL质量差,容量问题动参数,质量问题推动绑定变量改造,热点大对象用KEEP固定,最后才考虑flush或重启这类应急手段。建立监控基线,定期复查命中率指标,才能让共享池长期保持健康状态。
Oracle共享池Shared PoolSGA优化修改时间:2026-09-05 13:44:41