是不是很难准确地分配区别池所需内存数?自动共享内存管理特性使得自动将内存分配到最需要地方去成为可能
无论您是个刚入门 DBA 还是个经验丰富 DBA您肯定至少看到过次类似以下:
ORA-04031:unable to allocate 2216 s of shared memory (\"shared pool\"... ...
或者这种:
ORA-04031:unable to allocate XXXX s of shared memory (\"large pool\",\"unknown object\",\"session heap\",\"frame\")
或者可能这种:
ORA-04031:unable to allocate s of shared memory (\"shared pool\",\"unknown object\",\"joxlod:init h\", \"JOX:ioc_allocate_pal\")
第种原因很明显:分配给共享池内存不足以满足用户请求(在某些情况下原因可能不是池本身大小而是未使用绑定变量导致过多分析造成碎片这是我很喜欢个主题;但目前让我们把重点放在手头问题上)其它分别来自大型池和 Java 池空间不足
您需要解决这些情况而不作任何和应用相关修改那么有哪些方案可选呢?问题是如何在 Oracle 例程所需所有池的间划分可用内存
馅饼如何分?
正如您所了解个 Oracle 例程系统全局区域 (SGA) 包含几个内存区域(包括缓冲高速缓存Cache、共享池、Java 池、大型池和重做日志缓冲)这些池在操作系统内存空间中占据了固定内存数;它们大小由 DBA 在化参数文件中指定
这 4个池(数据库块缓冲高速缓存Cache、共享池、Java 池和大型池)几乎占据了 SGA 中所有空间(和其它区域相比重做日志缓冲没有占据多少空间对我们这里讨论无关紧要)作为 DBA您必须确保它们各自内存分配是充足
假定您决定了这些池值分别是 2GB、1GB、1GB 和 1GB您将设置以下化参数来为数据库例程规定池大小
db_cache_size = 2gshared_pool_size = 1glarge_pool_size = 1gjava_pool_size = 1g
现在仔细看下这些参数坦白讲这些值是否准确?
我相信您定会有疑虑在实际中没有人能够为这些池指定确切内存数 — 它们太依赖于数据库内部处理而处理特性随时在变化
下面是个举例场景假定您有个典型、大部分属于 OLTP 数据库并且为缓冲高速缓存Cache分配专用内存比为纯 OLTP 数据库(现在已经很少见了)分配要少有天您用户放开了些非常大全表扫描以创建当天结束报表Oracle9i 数据库为您提供了在线修改内存分配功能但由于提供总物理内存有限您决定从大型池和 Java 池中取出些内存:
alter system db_cache_size = 3g scope=memory;alter system large_pool_size = 512m scope=memory;alter system java_pool_size = 512m scope=memory;
这个解决方案能够很好地工作段时间但是接着夜间 RMAN 作业(它们使用大型池)开始了大型池将立即出现内存不足同样您从数据库高速缓存Cache中取出些内存来补充大型池以挽救这种局面
RMAN 作业完成然后启动个广泛使用 Java 批处理接着您开始看到和 Java 池相关因此您(再次)重新分配池以满足 Java 池和数据库高速缓存Cache上内存需求:
alter system db_cache_size = 2G scope=memory;alter system large_pool_size = 512M scope=memory;alter system java_pool_size = 1.5G scope=memory;
第 2天早上OLTP 作业恢复在线这个循环又完全重复!
解决这种恶性循环种替代思路方法是永久设置每个池最大需求不过这么做话您分配总 SGA 可能超出可用内存 — 从而在为每个池分配内存数不足时将增加交换和分页风险人工重新分配思路方法(虽然不实际)目前看起来很不错
另种替代思路方法是将值设为可接受最小值不过当需求增长且内存不能完全满足时性能将受到影响
注意在所有这些举例中分配给 SGA 总内存保持不变而池的间内存分配根据即时需求进行修改如果 RDBMS 将自动探测来自用户需求并相应地重新分布内存分配那不是很好吗?
Oracle 数据库 10g 中自动共享内存管理特性正好能够实现这目您可以决定 SGA 总大小然后设置个名称为 SGA_TARGET 参数这个参数决定 SGA 总大小SGA 内部各个池将根据工作负载动态地进行配置实现自动内存分配仅仅需要 SGA_TARGET 参数个非零值
设置自动共享内存管理
让我们看看该特性是如何工作首先确定 SGA 总大小您可以通过确定现在分配了多少内存来估计这个值
SQL> select sum(value)/1024/1024 from v$sga;SUM(VALUE)/1024/1024-------------------- 500
此时 SGA 当前总大小近似为 500MB并且这个值将变为 SGA_TARGET 值接下来执行语句:
alter system sga_target = 500M scope=both;
这种思路方法不需要为各个池设置区别值;因而您将需要在参数文件中使它们值为零或全部删除它们
shared_pool_size = 0large_pool_size = 0java_pool_size = 0db_cache_size = 0
再循环数据库使这些值生效
这个人工过程还可以通过 Enterprise Manager 10g 实施从数据库主页中选择 \"Administration\" 选项卡然后选择 \"Memory Parameters\"对于人工配置内存参数将显示标记为 \"Enable\" 按钮以及所有人工配置池值单击 \"Enable\" 按钮启用自动共享内存管理特性企业管理器将完成剩下工作
在配置了自动内存分配的后您可以利用以下命令检查它们大小:
SQL> select current_size from v$buffer_pool;CURRENT_SIZE------------ 340SQL> select pool, sum(s)/1024/1024 Ms from v$sgastat group by pool;POOL MBYTES------------ ----------java pool 4large pool 4shared pool 148
正如您所看到所有池都从 500MB 总目标大小中自动进行分配(参见图 1)缓冲高速缓存Cache大小是 340MBJava 池是 4MB大型池是 4MB共享池是 148MB它们合起来总大小为 (340+4+4+148=) 496MB近似和 500MB 目标 SGA 大小相同
图 1:池分配
现在假定提供给 Oracle 主机内存从 500MB 减少为 300MB这意味着我们必须减少总 SGA 大小我们可以通过减小目标 SGA 大小来反映这种变化
alter system sga_target = 300M scope=both;
现在查看各个池我们可以看到:
SQL> select current_size from v$buffer_pool;CURRENT_SIZE------------ 244SQL> select pool, sum(s)/1024/1024 Ms from v$sgastat group by pool;POOL MBYTES------------ ----------java pool 4large pool 4shared pool 44
占用总大小是 240+4+4+44 = 296MB接近于目标 300MB注意如图 2 所示当 SGA_TARGET 改变时如何自动重新分配池
图 2:在将 SGA 大小减少到 300MB 的后重新分配池
这些池大小是动态池将根据工作负载扩展以容纳需求增长或缩小以容纳另个池扩展这种扩展或缩小自动发生无需 DBA 干预这和本文开头举例区别让我们暂时返回到那个场景假定在分配后RMAN 作业启动指示需要个更大大型池大型池将从 4MB 扩展到 40MB以容纳需求这个额外 36MB 将从数据库缓冲中划出数据库块缓冲将缩小如图 3 所示
图 3:在对大型池需求增长的后经过重新分配池
池大小变化基于系统上工作负载因此不需要为最坏情况调整池大小 — 它们将根据需求增长自动调整此外SGA 总大小始终在由 SGA_TARGET 指定最大值的内因此不存在使内存需求增长比例失调(这将导致分页和交换)风险您可以动态地将 SGA_TARGET 增加至绝对最大值,这个绝对最大值是通过调整参数 SGA_MAX_SIZE 指定
哪些池不受影响?
SGA 中些池不受动态大小调整影响但是必须显式指定这些池其中值得注意是非标准块大小缓冲池以及 KEEP 池或 RECYCLE 池非默认块大小如果您数据库有个块大小为 8K而您想要配置 2K、4K、16K 和 32K 块大小池那么您必须手动设置它们它们大小将保持不变;它们将不会根据负载缩小或扩展当使用多种大小缓冲池、KEEP 池和 RECYCLE 池时您应当考虑这个原因此外日志缓冲不受内存调整影响 — 不管工作负载如何在参数 log_buffer 中设定值是不变( 在 10g 中还可以在 SGA 中定义种新池:流池 (stream pool)它用参数 streams_pool_size 进行设置该池也不受自动内存调整影响)
这就产生了个有趣问题如果您需要个非默认块大小池而且想自动管理其它池那么该如何办?
如果您指定了这些非自动调整参数中任意个(如 db_2k_cache_size)那么它们总大小将从 SGA_TARGET 值中减去以计算自动调整参数值以使 SGA 总大小保持不变例如假设值看起来像这样:
sga_target = 500Mdb_2k_cache_size = 50M
其余池参数未设置50MB 2KB 缓冲池为自动调整池(如默认块大小缓冲池 (db_cache_size)、共享池、Java 池和大型池)保留了 450MB当以种思路方法动态地调整不可自动调整参数(如 2KB 块大小池)——这种思路方法将影响到可自动调整部分大小可自动调整部分将重新调整例如将 db_2k_cache_size 值从 50MB 提高到 100MB 只为可自动调整参数剩余 400MB因此如图 4 所示,可调整池(如共享池、大型池、Java 池和默认缓冲池)自动缩小以将它们总大小从 450MB 减少到 400MB
图 4:配置非自动缓冲参数效果
但如果您有足够可用内存或者上述风险可能不是那么明显那应该如何办?如果这样话您可以通过不指定参数文件中参数 SGA_TARGET、通过在文件中将其设为 0或者通过使用 ALTER SYSTEM 动态地将其修改为 0 来关闭自动大小调整当 SGA_TARGET 被设为 0 时池当前值被自动设为它们参数
使用 Enterprise Manager
您还可以使用 Enterprise Manager 10g 来处理这些参数从数据库主页中单击超链接 \"Memory Parameters\"这将显示个类似于图 5 中屏幕
图 5:在 Enterprise Manager 中调整自动共享内存管理
注意红圈中项目:数据库在 Automatic Shared Memory Management 模式下运行总大小为 564MB — 和在参数 SGA_TARGET 中指定值相同您可以在此修改它然后单击 Apply 按钮接受这些值;可调整参数将自动调整
为每个池指定个最小值
假定您将 SGA_TARGET 设为 600MB并且各个池已自动分配:
池大小 (MB)缓冲池404Java 池4大型池4共享池148
看看上述值您可能推断 4MB Java 池和大型池可能有点不足;这个值在运行时无疑需要增加因此您可能想确保这些池至少在最初时具有更高值比如说分别为 8MB 和 16MB您可以通过在参数文件中显式地指定这些池值或动态使用 ALTER SYSTEM 来实现这目(如下所示)
alter system large_pool_size = 16M;alter system java_pool_size = 8M;
现在查看这些池您可以看到:
SQL> select pool, sum(s)/1024/1024 Ms from v$sgastat group by pool;POOL MBYTES------------ ----------java pool 8large pool 16shared pool 148SQL> select current_size from v$buffer_pool;CURRENT_SIZE------------ 388
池重新分配显示如下:
池大小 (MB)缓冲池388Java 池8大型池16共享池148
注意 Java 池和大型池是如何分别被重新配置为 8MB 和 16MB并且注意为了使总 SGA 保持在 600MB 以下缓冲池已从 404MB 减少为 388MB当然这些池仍然由自动共享内存管理控制 — 它们大小将根据需求缩小或扩展您显式指定值为池大小设定了个下限;它们将永远不会缩小到低于这个界限
结论
Oracle SGA 中各种池内存需求不是静态 — 相反它们根据系统上需求而变化Oracle 数据库 10g 中自动共享内存管理特性通过动态地将资源重新分配到最需要它们地方同时施加个指定最大值以防止分页和交换使得 DBA 能够更有效地管理系统内存更有效内存管理还带来了更少内存需求这使得更精简硬件更加可行
有关自动共享内存管理特性更多信息请参见 Oracle 数据库性能调整指南第 7 章
最新评论