ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

Copyright (c) 2019, Oracle. All rights reserved. Oracle Confidential.
ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)
 
ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)
 
ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1) ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1) ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1) ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)To Bottom ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

文档内容

  用途
  常见 Bug
  问题和答案
  在 SGA 池中内存是如何分配和释放的?
  什么是子池(Subpools)?
  什么是保留区域?
  SGA 中的各池的作用是什么?
  ORA-4031 错误是什么?
  我的保留区域大小是否合适?
  是否有办法找到一个共享池的“正确”大小?
  我的 SGA 中有多少空闲内存可用?
  10g 的 ASMM 和/或 11gAMM 自动化地管理了什么?
  我默认有多少子池?
  我应当如何控制使用的子池的数量?
  是否所有的 ora-4031 错误都记录在 alert log 里?
  我们应当如何查看 V$SGASTAT 中的"miscellaneous"结构的分解数据?
  什么数据库参数与 ORA-04031 问题有关?
  我们应该查看 RDA 中的哪些信息来帮助诊断 4031 错误?
  在默认的 4031 追踪文件中有哪些信息是相关的?
  在 Statspack/AWR 报告中有哪些信息是与 4031 错误相关的?
  我们如何确定是否有应用的问题导致了这个错误?
  没有使用绑定变量
  多个子游标
  高解析率
  参考

适用于:

Oracle Database - Enterprise Edition - 版本 8.1.5.0 和更高版本
Oracle Database Cloud Schema Service - 版本 N/A 和更高版本
Oracle Database Exadata Cloud Machine - 版本 N/A 和更高版本
Oracle Cloud Infrastructure - Database Service - 版本 N/A 和更高版本
Oracle Database Backup Service - 版本 N/A 和更高版本
本文档所含信息适用于所有平台

用途

这篇文档用于

  • 帮助读者理解 ora-4031 错误的原因
  • 收集需要的诊断信息来缩小错误的范围
  • 回答一些关于 ora-4031 的常见问题

上次更新于 2010年6月

ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1) 视频 - FAQ for ORA-4031 Errors (08:00) ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

注意:
如果你想要进一步探索这个错误,请加入社区讨论 'Diagnosing and Resolving ORA-4031 errors'。这里你可以提出问题,从其他人那里获取帮助,并且分享你对这篇文档的经验。

常见 Bug

Note: 4031.1 提供了可按照版本查询的最新的 Bug 信息。

注意:下面所引用的脚本名字是封装的脚本,并且可以在 Note 430473.1 ORA-4031 Common Analysis/Diagnostic Scripts 中找到。查看文章中标记为 'Software Requirements/Prerequisites' 的部分。您可以点击 'Click here' 链接下载 zip 文件。这些脚本随时更新,请每次都确认你下载到最新版本的脚本。

问题和答案

在 SGA 池中内存是如何分配和释放的?

SGA 是由固定的区域组成的,例如 Log Buffers 和 Buffer Cache(s),以及内存池(Shared Pool,Large Pool,Java Pool,从 10g 开始还有 Streams Pool)。这些不同的池中分配的内存被划分为 heap,这些 heap 又可以由一个或者多个 subheap 内存结构所组成。

ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

这类似于一个表空间中的很多段。表空间是 heap 而段是 subheap。段中的 extent 类似于在“父” subheap 中的各种 subheap。在共享内存区域中的目标与表空间是相同的 - 避免碎片。为了实现这点,我们分配的内存块要能够最好的匹配请求的内存,在需要时合并邻近的空余空间,并且探测可以释放和重用的内存。

在这些池中,我们使用空闲列表 buckets。他们是空闲列表的结构体,并且每一个列表对应一个特定的大小。Oracle 以二进制搜索空闲列表的大小,以找到合适的空闲列表。返回大于或者等于要求的大小的第一个 bucket。数据库启动时,在每个池中创建了不同大小的内存块。我们会继续遍历空闲列表,直到我们找到一个 bucket 指向一个足够大的内存区间。共享池会利用 Least Recently Used (LRU)算法来“老化”长久未用的内存结构。

要更好的理解这个问题,请看如下的 heapdump 信息,这是一个空闲列表 bucket 的总结:

Free List Bucket Summary : 
Bucket 0 [size=32 ] Count= 0 Av.Size= 0.00 Max= 0 
Bucket 1 [size=40 ] Count= 443 Av.Size= 40.00 Max= 40 
Bucket 2 [size=48 ] Count= 1850 Av.Size= 48.00 Max= 48

这里显示 bucket1 有 443 个内存块(chunk),其中最大的是 40byte,平均是 40byte。Bucket 2 这个空闲列表中内存块的大小是 40 到 48byte 之间。当一块空间被释放时,它会被添加到小于或等于块大小的 bucket 里。如果你发现共享池中的可用内存越来越小,而不是有大块和小块内存的混合,这可能意味着应用导致了碎片,而且更有可能的,在未来,某一个大的内存请求会因 ora-4031 错误而失败。 参考我们如何确定是否有应用的问题导致了这个错误?, 其中解释了如何追踪低效的代码。

共享池和大池划分他们的内存区域到子池中(从 9i 开始)。每一个子池会有空闲列表 Bucket,包含指向这个子池内部的内存块的指针。其它的池则没有子池,只有一个大的内存区域,和一个上述的空闲列表。

当一个内存块被分配到内存池中时,它会被赋予一个内存类型,包括 PERMANENT,FREEABLE 或者 RECREATABLE。这些内存块之后会被赋予一种池中的内存结构或者元素。例如"KGLS heap"。这些内存结构或元素并不总是会在数据字典中被追踪或者注释(特别是 PERMANENT 类型的那些)。

块的类型:

Normal (freeable) chunks – 这些块所分配的方式使得当内存处理结束时,用户可以显式的释放内存块。

Free chunks – 这些块是空闲的,当有小于或等于块大小的请求进入池中时,就可以重用。

Recreatable chunks – 这是一种特殊形式的"freeable"内存。当它们没有被 pin 的时候,这些块放在 LRU 列表里。如果需要内存,我们会到 LRU 列表内释放一段时间没有使用的“Recreatable”内存。

Permanent chunks – 这些块以不同的方式分配。一些块分配后会在实例的整个生命周期中存在。一些块分配后只要可用,会被内部反反复复的使用。

通过设置事件,可以把 permanent 块标注为其它类型的内存块来进行调试。

什么是子池(Subpools)?

在 Oracle 9i 和之后的版本,共享池可以被划分为子池。每个子池是一个小号的共享池,有它自己的空闲列表,内存结构条目,和LRU列表。这是一个对共享池和大池的可扩展性的改变,现在每一个子池都由一个 child latch 来保护,因此可以增加这些池的吞吐量。这意味着不再有之前版本的对于共享池和大池的单独 latch 的竞争。共享池中的保留区域也被平均的划分到每个子池中。

当你遇到 ora-04031 时,trace 会显示错误发生在哪个子池中。

例如:
ORA-04031: unable to allocate 4192 bytes of shared memory ("shared pool","SELECT /*+ FIRST_ROWS */ * F...","sql area (6,0)","kafco : qkacol"):4031:375:2008:ocicon.c

这个例子中,错误发生在第六个子池中。

使用子池的缺点是,有些情况下,个别子池被过分利用了。一旦子池选定,即使其他子池有合适的可用内存,内存块的搜索也可能失败。从 10g 开始,我们确实有这样的功能,允许当内存请求在选定的子池中无法满足时,“交换”到其他子池进行搜索,但这功能不可能对所有的内存结构和元素都起作用。

注意:有一小部分功能会跨子池的利用内存块。换句话说,就是跨越多子池的条带化使用内存。

这极少有文档记录,一般来说,内存请求会以轮转的方式,从一个“随机”的子池中找到它需要的内存块。

不平衡的使用子池会导致 ORA-04031。常见的是在"session param values"内存结构上的内存分配失败。在 9i 及更高版本,需要为每个配置了的 process 分配内存来存储动态参数。在启动时,会选中一个子池来管理所有的"session param values"条目。如果 PROCESSES 参数设置的非常高,并且又没有非常高的并发连接,这可能导致在子池中不必要的永久内存分配,并且可能引发 ORA-04031 问题。一般来说,拥有多个共享池 latch 所带来的性能上的改善要超过由于过度利用子池而可能带来的问题。

终端用户是看不到子池的。他们被隐藏在共享池和大池的使用下。注意:如果共享池使用子池,只要 LARGE_POOL_SIZE>0,就会自动的在大池中创建子池。

参考(这个问题看上去影响了很多 Bug):
Bug 4184298 - Subpool imbalance for "session parameters"

什么是保留区域?

数据字典缓存或者库缓存上未命中的代价要比 Buffer Cache 上的未命中更高。由于这个原因,共享池应该设计的足够大,能够保证经常用的数据都被缓存起来。如果在共享池里没有足够的空余空间,那么 Oracle 必须搜索和释放足够的内存来满足这个请求。这个操作会毫无疑问的占有 latch 资源比较长的时间,导致对其它并发的内存分配的尝试造成影响。大的空间分配请求失败的代价可能是非常昂贵的,因为他可能导致很多小一些的内存片被从 Shared Pool 内存中清理出去,来为大的空间请求让出位置。

默认的,Oracle 在共享池中配置一个小的保留池(或保留区域)。这块内存可以在普通的共享池列表中的空间不可用时,被用来满足大的连续的分配请求。
典型的大的分配请求操作有,PL/SQL,触发器编译,或者加载 Java 对象。当保留池中分配的内存被释放后,它会交还给保留池。

可以放置在保留池中的内存分配的最小大小通过隐含参数 _shared_pool_reserved_min_alloc 来控制。在近期版本上默认设置是 4400byte,可以被最低设置到 4000byte。
如果从普通共享池空闲列表上无法找到足够大小的内存块,那么大于 _shared_pool_reserved_min_alloc 的内存分配请求可以从保留区域的列表中分配。

如果 ORA-4031 错误消息中指出的失败大小或者 V$SHARED_POOL_RESERVED 中的 LAST_FAILURE_SIZE 列的大小大于 _shared_pool_reserved_min_alloc,这意味着需要增大保留区域来适应这些大的内存请求。

保留池大小可以通过指定 shared_pool_reserved_size 来设置为一个固定的大小,也可以指定隐含参数 _shared_pool_reserved_pct 来指定一个比例。如果同时设置了两个参数,以隐藏参数 _shared_pool_reserved_pct 为准。

在一些应用环境,5% 太小了。如果一个 ORA-4031 问题指向一个很大的内存请求失败,那么通过手动设置 SHARED_POOL_RESERVED_SIZE 来增大保留区域大小,或者如果使用了 SGA_TARGET>0,改变隐含参数 _shared_pool_reserved_pct  到 10 或者 15(参考下例)来确保当共享池增长或者收缩时,保留区域也会同样变化。

视图 V$SHARED_POOL_RESERVED 可以被用来确定失败的请求大小,和共享池保留区域利用率。Document: 430473.1 ORA-4031 Common Analysis/Diagnostic Scripts 包含一个脚本来查询这个视图。

警告: 
如果你决定使用 SHARED_POOL_RESERVED_SIZE 参数并且 SGA_TARGET>0,你可能会在大的内存请求上遇到 ORA-4031 的情况,因为 MMAN 进程可能会一直增大共享池大小,而保留区域大小是恒定的。因此,保留区域在开始时可能是共享池的 10%,但是随时间变化,可能最终变成 2% 或者 3%(相比新的共享池大小,可能比期望的小很多)。

保留区域处理大些的内存请求,试图减少共享池随时间的推移产生碎片的几率。

SQL> alter system set "_shared_pool_reserved_pct"=10 scope=spfile

或者在 pfile 中增加

"_shared_pool_reserved_pct"=10

对于大的分配,Oracle 尝试按照如下顺序在共享池中分配空间

1.  从共享池的非保留区域。

2.  从保留池。如果在共享池的非保留区域没有足够的空间,那么 Oracle 检查是否在保留区域有足够的空间。

3.  如果在共享池的非保留区域和保留区域都没有足够的空间,那么 Oracle 尝试去释放足够的空间来分配。接下来重试共享池中的非保留区域和保留区域。这些小规模的清理会从 LRU 列表中清除一段时间没用过的 RECREATABLE/FREEABLE 的内存块。

SGA 中的各池的作用是什么?

SGA 中的共享池部分包含了库缓存,数据字典缓存,并行执行消息的 Buffer 和控制结构。库缓存包括共享 SQL 区域,私有 SQL 区域(如果是共享服务器配置的话),PL/SQL 过程和包,以及控制结构比如 LOCK 和库缓存句柄。当 SQL 语句被解析时,我们从共享池中分配内存,来存储到共享的 SQL area。内存的大小依赖于语句的复杂性。理想情况下,共享池应被用来缓存共享 SQL,并且避免由于收缩共享 SQL 缓存导致的性能开销。

Oracle 的很多特性,比如 Recovery Manager (RMAN),并行处理 I/O slave 进程,和共享服务器的设计中都会用到大的共享内存块。这些特性会给共享池带来不必要的压力,因此我们推荐使用 LARGE_POOL_SIZE 定义一个大池,或者使用 SGA_TARGE 来减少共享池在这些场景下的内存压力。

JAVA Pool 是被用来分配内存给 JVM 中和会话相关的 Java 代码和数据。取决于 Oracle 服务器的运行模式,Java Pool 的内存以多种不同方式利用。

如果使用 Streams 功能,你可以配置 Steams Pool 来管理此功能需要的内存分配。

共享池使用一个与 Buffer Cache 类似的 LRU 算法。因此,调节共享池比其它池更加复杂。大多数时候,如果 ora-4031 发生在其它的内存池,这意味着池太小,你必须增大出问题的池来避免问题在将来继续发生。

通常来说,这些池的默认设置是足够的,但是要手动的调节这些池,你可以修改参数 LARGE_POOL_SIZE,STREAMS_POOL_SIZE,和 JAVA_POOL_SIZE。如果使用 SGA_TARGET,MMAN 进程会根据需要自动调节这些池。

ORA-4031 错误是什么?

SGA 中的内存池由不同大小的内存块组成。当数据库实例启动时,大量的内存块分配到不同的池中并且由空闲列表哈希 bucket 追踪。随着时间推移,由于内存块被分配和回收,内存块会根据它们的大小在池中的不同空闲列表 Bucket 中移动。当 Oracle 不能找到一个足够大的内存块来满足用户操作所带来的内部分配请求的时候,ORA-4031 错误就可能在 SGA 的任何一个池中出现。

共享池的管理与其它内存池不同。共享池存储数据字典和库缓存相关的信息。然而,这些内存区域使用空闲列表和最少最近使用(LRU)算法管理。在搜索所有的空闲列表,老化 LRU 列表上所有可能的对象,并且扫描空闲列表多次之后,共享池上才会发出 ORA-4031 错误。这意味着 ORA-4031 很难预测。可能有很多的因素一起导致了 ORA-4031,错误发生时的 trace 信息是有关于当时内存条件下“受害者会话”,而不是原因。分配的算法非常复杂,下面是一个内存分配算法的简化版本:

scan regular free list for match, if not found
 large request, scan reserved list 
   if (chunk found) 
      check chunk size and perhaps truncate 
   if (chunk is not found) 
      scan regular free list 
          if (chunk found) 
             check chunk size and perhaps truncate 
             all done 
          if (chunk is not found) 
              do LRU operations and repeat

small request, scan regular free list 
   do LRU operations and repeat search
    if (chunk found) 
       check chunk size and perhaps truncate 
       all done 
    if (chunk is not found) 
   do LRU operations and repeat

注意:有内部检查来限制报出 ORA-4031 错误前所进行搜索的次数。

空闲空间的总数可以从 v$sgastat 中获得,但这是不重要的。重要的是,通过 LRU 操作可以释放或者融合的最大的块的大小。从 heapdump 我们可以看到空闲列表 Bucket 和每个 Bucket 中内存块的信息。

Free List Bucket Summary : 
Bucket 0 [size=32 ] Count= 0 Av.Size= 0.00 Max= 0 
Bucket 1 [size=40 ] Count= 443 Av.Size= 40.00 Max= 40 
Bucket 2 [size=48 ] Count= 1850 Av.Size= 48.00 Max= 48

这里显示 bucket1 有 443 个内存块(chunk),其中最大的是 40byte,平均是 40byte。Bucket 2 包含的内存块的大小是 40 到 48byte 之间。在这个例子中平均大小是 40byte,最大是 40byte。找到在内存池中什么导致了碎片并不总是可行的。有时问题是Oracle 功能导致的,但是很大一部分的情况中,低效的应用代码才是根本原因。

ORA-4031 错误可以发生在 Large Pool,Java Pool,Streams Pool (10g 新增),或者 Shared Pool 中。错误信息会指出哪个池出了问题。如果错误指出问题不在共享池中,这通常意味着对应用环境来说,出问题的池配置的太小了。将出问题的池增大 15%,然后观察后续的问题。如果使用 10g ,Automatic Shared Memory Management (ASMM)功能,MMAN进程会随着时间推移,尝试根据内存需要收缩或者增长 SGA 中不同的组件。如果你在 Large Pool,Streams Pool 或者 Java Pool 中遇到了 ORA-4031 错误, 那么您可能需要增长 SGA_TARGET,使 MMAN 可以在背后管理更多的内存。

共享池的调节要更复杂一些。例如

ORA-04031: unable to allocate 4192 bytes of shared memory ("shared pool","SELECT /*+ FIRST_ROWS */ * F...","sql area","kafco : qkacol"):4031:375:2008:ocicon.c

在这个例子中,问题发生在共享池。错误消息也包含内存请求失败的大小的信息。在我们的例子中,请求 SQL Area 中 4192byte 时失败。

注意:在 ASM 环境中也用到共享池。10.1.x ASM 实例上有 ORA-4031 的问题,原因是默认值太小了,不能适应磁盘组管理活动的需要。在这个案例中,应设置 SHARED_POOL_SIZE 到 50M,如果问题仍然存在,逐次增加 10M。

Note 146599.1 Diagnosing and Resolving Error ORA-04031

我的保留区域大小是否合适?

ora-4031 错误中引用了大的失败请求意味着保留区域过于破碎了。你可以用 Note 430473.1 中的脚本调查保留区域的内存使用。

ReservedAnalysis.sql

Request Misses = 0 可能意味着保留区域太大了。Request Misses 总是增长,但是 Request Failures 不增长可能意味着保留区域太小.这种情况下清理 Shared Pool 可满足内存需要。Request Misses 和 Request Failures 总是增长意味着保留区域太小并且清理 Shared Pool 不会有帮助(很可能遇到 ORA-04031)。

你也可以调查你的保留区域的大小的效率。目标是让"Hit %"尽可能的靠近 100。 注意:保留区域中的失败并不总是等同于 ORA-4031 错误。我们执行小规模的清理来尝试匹配内存请求,在很多情况下,我们会找到请求的内存并且避免错误。如果你增大保留区域的大小,那么你可能将有用的内存从共享池中拿走。我们推荐你同步的增大共享池和保留区域的大小。

col requests for 999,999,999 
col last_failure_size for 999,999,999 head "LAST FAILURE| SIZE " 
col last_miss_size for 999,999,999 head "LAST MISS|SIZE " 
col pct for 999 head "HIT|% " 
col request_failures for 999,999,999,999 head "FAILURES" 
select requests, 
decode(requests,0,0,trunc(100-(100*(request_misses/requests)),0)) PCT, request_failures, last_miss_size, last_failure_size 
from v$shared_pool_reserved;

是否有办法找到一个共享池的“正确”大小?

你可以使用参数 SHARED_POOL_SIZE 手动的配置共享池,或者 SGA_TARGET(10g 及以上)自动调节。为共享池分配的部分内存是附加内存开销(基于一些内部参数的设置)。10g 之前,附加的内存开销在 SHARED_POOL_SIZE 参数设定“之上”,但是不被参数 SHARED_POOL_SIZE 所反映。当你在 10g 之前查询 V$SGASTAT时,这看上去是一个计算错误。

例如

SHARED_POOL_SIZE=64M 
Overhead=12M

SQL> Select sum(bytes) "Total Mem" from v$sgastat where pool='shared pool';

Total Mem 
----------- 
   79691776

在 10g 上,附加内存开销现在被包括在 SHARED_POOL_SIZE 设定中了。由于没有考虑附加内存开销,一些客户升级到 10g 后遇到了内存问题。在上例中,如果 SHARED_POOL_SIZE 手动设置到 64M 并且附加开销保持不变,这意味着可用的共享池内存只有 54525952bytes。

注意:像 105813.1 SCRIPT TO SUGGEST MINIMUM SHARED POOL SIZE 文章中这样的脚本,在旧版本的数据库中是有用的,但在 Oracle9.2.x 或者更高的版本并不是总能工作。有关 10g *享池大小调节的其它问题,参考

Note 270935.1 Shared pool sizing in 10g
Note 430473.1 ORA-4031 Common Analysis/Diagnostic Scripts

我的 SGA 中有多少空闲内存可用?

你可以从视图 V$SGASTAT 中看到共享池的空闲内存。视图被分解成内存结构表条目,例如 'library cache','KGLS heap','CCursor'。10g 之前,这个视图只能追踪少量的表条目,因此一些小的内存结构被集中到一起,归入 'miscellaneous' 条目。

10g 的 ASMM 和/或 11gAMM 自动化地管理了什么?

在 10g 上,当 SGA_TARGET>0,会打开自动共享内存管理(Automatic Shared Memory Management)功能。ASMM 会为 SGA 中的这些组件管理“最好”的大小

  • Shared Pool
  • Large Pool
  • Java Pool
  • Buffer Cache (db_cache_size所管理的默认的部分)
  • Streams Pool (10g Release 2 新增)

内存的移动是以”Granule”为单位进行的。你可以通过通过查询 V$SGAINFO 找到数据库的 granule 大小。Note 947152.1 指出了使用大 granule 时的问题。默认的非常大的 SGA 会使用非常大的 granule。

其它的 Buffer Cache(通过参数 DB_nK_CACHE_SIZE,DB_KEEP_CACHE_SIZE,DB_RECYCLE_CACHE_SIZE 管理),Log Buffer 和 Fixed SGA areas 不会被 MMAN 自动调节。然而,这些设置确实会影响 SGA_TARGET 设置中 MMAN 实际可用的内存。

SGA_TARGET 可以在 SGA_MAX_SIZE 设置的范围内动态调节。注意:对于一些平台有一些限制,取决于在这些平台的内存中 LOCK_SGA 如何工作。

案例学习:
配置 SGA_TARGET 到 4G。

并且配置

DB_KEEP_CACHE_SIZE=256M 
LOG_BUFFER=200M
DB_4K_CACHE_SIZE=512M.

并且手动设置 SHARED POOL 的最小值(SHARED_POOL_SIZE=1G)。

这对 MMAN 有什么影响?这意味着 MMAN 无法使用整个 4G 内存对自动调节内存组件进行管理。MMAN 只能访问 2,206,203,904 bytes。

据上述配置,如下的内存必须是 SGA 的一部分

Log Buffers             209,715,200 
   Keep Buffer Cache 268,435,456 
   4K Buffer Cache     536,870,912 
+ Shared Pool         1,073,741,824 (手动指定这个值意味着共享池不能收缩到更小)
------------------------------------  
Total                       2,088,763,392

手动的为 SGA 中的自动调节组件设置一个最小值是有一些益处的,但是它对 MMAN 根据需要增长和收缩不同的组件时所能访问的内存数量也有影响。我们推荐对 SGA 中的自动调节组件进行默认/显式的设置。要评估 ASMM 如何工作,运行 Note 430473.1 中的脚本

SGAComponents.sql (for 10.2.x)
SGAComponents11g.sql (for 11g)

设置 ASMM 的一个经验法则是

SGA_TARGET = 256M * # of CPUs

这个对你的应用内存使用等等做了很多的假设,而且更适当的是使用上面列出的查询对受管理的各池的大小进行监控。

1.  观察趋势并找到上面脚本中的不同的池的正确的最小值。
2.  在你的初始化文件中,使用这些值来作为池参数大小的初始设置。
3.  SGA_TARGET 设为高于固定设置和初始设置总和的 25%。
4.  SGA_MAX_SIZE设为高于SGA_TARGET 25%。注意:这一步不是适用于所有环境的。SGA_MAX_SIZE 的内存在 Oracle 启动时分配。大多数客户都难以理顺 Oracle 内存的分配,但却不能在需要时自动处理。一些客户发现,当有业务流程周期性的需求更多的 SGA 内存时,将 SGA_TARGET 提升到 SGA_MAX_SIZE,比把这些内存给应用程序日常使用更有益处。

警告:在 10.2.x 上,有很多与 ASMM 和 ORA-4031 相关的问题报告。很多客户并不为自动调节池设置最小值,而是依赖于 SGA_TARGET 和 MMAN 去根据需要移动内存。内部的测试以及和开发部门的讨论表明,最好是为这些池找到一个最小值,并且手动的设置到 spfile 或者 init 参数文件中去。 作为起始点,查看 v$sga_dynamic_components 中的数据,手动的给这些池赋值到当前值的 70 到 75%。如果随着时间推移,有收缩 share pool 到那个值之下失败的迹象,那么将默认设置减少 10%,监控新值是否是一个更好的最小设置。这会帮助减少 Buffer Cache 和不同的池之间出现过量的钉住内存的情况。

从 11g 开始,自动调节也会管理 PGA_AGGREGATE_TARGET。 11g 自动调节(AMM)通过 MEMORY_TARGET>0 来配置。Note 443746.1 指出了 11g 自动调节上的改变。

注意:在 11g 中,即使当 MEMORY_TARGET 和 SGA_TARGET 被显示的设置为 0 时,对 SGA 中池的 IMMEDIATE 内存请求也可以在 SGA 中移动。参考 Note 1269139.1

我默认有多少子池?

子池的数量计算有一个简单的算法。首先,在 9i 中一个子池至少有个 128MB,在 10g 中至少 256MB。第二,系统中每 4 个 CPU 可以有一个子池,最多 7 个子池。子池的数量可以用初始化参数 _kghdsidx_count 明确的控制。没有参数可以明确控制每个子池的大小。

如果有人在 9i 上配置一个 12 CPU 的系统,300MB 的共享池,Oracle 会创建 2 个子池,每个 150MB。如果共享池大小增大到 500MB,Oracle 会创建 3 个子池,每个 166MB。

因为 128MB(甚至 10g 上的 256MB)子池在很多应用环境中可能偏小,每个子池中的内存会倾向于需要增大。没有参数可以改变子池的最小值。唯一的办法是在一个固定的共享池大小基础上减少子池的数量,或者增大共享池使得子池大小增长。 请注意增长共享池大小并不一定增长子池的大小,因为如果系统上有很多 CPU,子池的数量也会增长。

10.2.0.3 及以上的变化:根据 bug 4994956,10g 或更高版本上,算法是将每个子池增长到 512M。

我应当如何控制使用的子池的数量?

变量 _kghdsidx_count 控制了使用的子池的数量。将这个参数设置为 1 会使共享池的行为回退到 8.1.7 版本。即,一个子池。

SQL> alter system set "_kghdsidx_count"=1scope=spfile;

或者把这行加入 pfile

"_kghdsidx_count"=1

注意:子池的创建是在启动过程中 SGA 创建时发生的。上述的 2 个例子中,数据库都必须重启来改变子池的数量。对 _kghdsidx_count 的改变也会改变大池中的子池数量。

 

警告:减少子池的数量会对性能有显著的影响,特别是在 RAC 配置,高并发系统,或者有非常大的池的数据库实例中。改变这个参数会影响共享池, 共享池保留区域和大池。

当通过 _kghdsidx_count 手动的设置子池的数量的时候,推荐的做法是逐渐的进行改动,监控性能影响,以避免任何剧烈的影响。

相反的的,增加子池的数量而不增加池的整体大小的话,由于子池大小变小,可能导致空间问题。

 

是否所有的 ora-4031 错误都记录在 alert log 里?

不。一些错误只在客户端显示。在 11g 之前,在常规用户进程上发生的任何 ora-4031 错误都不会被记录在 alert log 中。也有一些情况,alert log 中报出了 ora-600 和 ora-7445 错误,但是这些内部错误实际是一个 ora-4031 内存问题的副作用。这些内部错误的日志通常包含在 ora-4031 trace 中。

注意:在 11g 中,bug 9209518 指出甚至当内存请求未得到满足,但后来我们通过执行内部 LRU 操作满足了这个内存请求的情况下,我们也会生成 ora-4031 的 incident trace。例外情况是,当 ora-4031 错误发生的非常频繁,有些 trace 文件可能因为防止泛滥的设置而没有产生。

我们应当如何查看 V$SGASTAT 中的"miscellaneous"结构的分解数据?

当查询 v$sgastat 时,有些情况下你会看到一个非常大的"miscellaneous"数值。直到 Oracle 10g Release 2,SGA 内部结构的基本设计仍然没有变化。在数据字典里,有一些对不同内存“注释”的条目表,我们在最大的内存“注释”或者结构上保留统计数据。因为我们只追踪某一些结构,所以小一些的结构被归纳到叫做 miscellaneous 的内存“注释”上。如果你运行 Note: 430473.1 中的 SGAStat.sql 脚本,这个脚本会报告出 V$SGASTAT 视图中有关共享池的最大的分配区域。你可以调整这个脚本来查看 SGA 的任何池。

根据 Bug 3663344,由于内存结构随着时间变化增长和收缩,在 V$SGASTAT 的统计数据中,偶尔有些不一致。一旦一个内存结构达到一个内部的控制大小,我们就会从一个通用性的条目"miscellaneous",将有关的内存结构的数据移动到一个特别的内存结构条目。常见的问题是在 v$sgastat 的某些内存结构上会看到负值,或者有时会看到一个不寻常的大的"miscellaneous"。

要挖掘"miscellaneous"区域的内存的唯一方法是获取一个 heapdump trace。你可以运行这个命令

alter system set events '4031 trace name HEAPDUMP level 536870914';

注意:在实例级别设置这个事件会生成大文件,如果 4031 错误发生频繁,会产生很多文件。这可能影响性能或者导致挂起(在一些案例中导致数据库崩溃)。使用如下命令关闭这个事件:

alter system set events '4031 trace name HEAPDUMP off';

在 4031 错误再次发生时,会获得一个 SGA 中内存的分解和 SGA 中最大的 5 个子堆的内存分解。这个场景下,你会看到在 trace 中列出的一个或者更多的最大的子堆是在 'miscellaneous' 中的。不幸的是,没有办法看到 'miscellaneous' 所有的分解,但我们只需要关注 'miscellaneous' 中高于预期的条目。

使用如下步骤来即时获取内存 dump

alter system set events 'immediate trace name heapdump level 536870914';
or

sqlplus /nolog 
connect / as sysdba 
oradebug setmypid 
oradebug unlimit 
oradebug dump heapdump 536870914 
oradebug tracefile_name 
oradebug close_trace

关闭 SQL*Plus 会话,根据上面 'oradebug tracefile_name' 命令的输出找到 heapdump trace 文件。

如果问题实际上关联到永久内存结构(在 'miscellaneous' 条目下查看),那么除非你设置事件 10235 level 65536,否则没有其他方式获取这些内存区域的详细信息。这个事件应在 Oracle Support 的指导下设置。

什么数据库参数与 ORA-04031 问题有关?

  • CURSOR_SHARING

在 Literal replacement(字面值取代)特性中,Oracle 通过取代 SQL 中的字面值来减少应用在共享池中占用的空间,并且降低硬解析。字面值被绑定变量取代,如果两个或者更多的会话执行相同的 SQL 语句,他们可以用带有绑定变量的相同的游标,而不是创建两个不可共享的游标。

例如,两个用户以 SCOTT 连接,并运行 SQL 语句"select ename from emp where empno = 20" 和 "select ename from emp where empno =100"。如果 cursor_sharing 设置成 FORCE,Oracle 会创建一个带绑定变量的游标,于是语句就等同于"select ename from emp where empno = :b1"。这两个用户会共享相同的游标对象而不是创建两个独立的库缓存父对象和它们对应的子对象。

这个参数有三个模式:

  • EXACT:不尝试进行 Literal replacement。
  • FORCE:所有的字面值都会被取代。语句会被共享,而不考虑字面值对执行计划的影响。
  • SIMILAR:所有的字面值都会被取代,但是,语句仅仅当游标有相同计划时才共享。

对对象执行 DDL,收集统计信息,或者赋予或收回权限都会导致失效(Invalidations)。你也会观察到关联的“library cache pin”等待。

参考:
Note 287059.1 Library Cache Pin/Lock Pile Up hangs the application 
Note 34579.1  WAITEVENT "library cache pin" Reference 
Note 115656.1 WAIT SCENARIOS REGARDING LIBRARY CACHE PIN AND LIBRARY CACHE LOAD LOCK

使用 SIMILAR 不是最优的。虽然带有字面值的游标有最好的执行计划,匹配的标准是基于字面值上的。这个用法会基于文字值创建一个小的哈希表,如果值是相同的,子游标会共享。这个行为会导致应用的共享池空间占用等同于使用 CURSOR_SHARING=EXACT 运行的结果。不再是创建很多独立的游标及它们自己的子游标,SIMILAR 在相同的父游标对象下创建很多子游标。如果你发现硬解析达到50/秒或更高(Snapshot/AWR),CURSOR_SHARING=EXACT 会比 SIMILAR 更有帮助的。

要评估这个参数当前设置的有效性,参考 Note 208918.1

  • CURSOR_SPACE_FOR_TIME

如果设置了这个参数,Oracle 不会在执行结束后 unpin 库缓存对象。这意味着随着越来越多的游标打开和执行,在库缓存中pin住的活跃的内存的数量在增加,可以被从共享池中老化出去的内存的数量在减少。这个参数要小心的使用,而且要知道应用在共享池中总共占有的空间。对此不了解的情况下设置这个参数会导致 ORA-04031。在 Session Cached Cursor 列表中的游标的 SQL area 堆并不被 pin 住。

一些站点使用这个参数,因为它避免了库缓存 pin 和 unpin 的代码执行。这并不是一个推荐的改善性能的参数。非常难以判断设置这个参数是否安全。

注意:在 10g 上这个参数可以帮助改善数据泵的性能。如果调查共享池中“sql area”区域发生的 ORA-04031 错误,查看是否 CURSOR_SPACE_FOR_TIME=true。这可能导致在 10.1.x 版本上"sql area"的分配增长并占用大部分的共享池。

  • DB_CACHE_SIZE

在 RDA 中检查这个参数设置的大小。如果使用 SGA_TARGET,它的默认设置为 0。如果在使用 SGA_TARGET 时对这个参数进行的设定,那么它会作为 MMAN 在收缩 Buffer Cache 时的最小值。

  • DB_nK_CACHE_SIZE

这个 SGA 内存组件是不能自动调节的,但是这项内存设定会影响 MMAN 实际可管理的内存。

  • DB_KEEP_CACHE_SIZE

这个 SGA 内存组件是不能自动调节的,但是这项内存设定会影响 MMAN 实际可管理的内存。

  • DB_RECYCLE_CACHE_SIZE

这个 SGA 内存组件是不能自动调节的,但是这项内存设定会影响 MMAN 实际可管理的内存。

  • JAVA_POOL_SIZE

如果使用 SGA_TARGET,它会默认设置为0。在使用 SGA_TARGET 时对这个参数进行的设定会作为 MMAN 尝试收缩 Java Pool 时的最小值。

如果你不使用 SGA_TARGET,这个内存区域的默认值通常是足够的,除非你的环境利用了大量的 JVM 对象。

如果你需要了解 JAVA Pool 中内存分配的更多细节,可以运行

> sqlplus /nolog
SQL> connect / as sysdba
SQL> alter session set events 'immediate trace name heapdump level 128';
  • LARGE_POOL_SIZE

Large Pool 是用来缓解共享池中较大的内存分配的负担的,包括共享服务器(UGA),并行处理(Buffer allocations),和 RMAN 备份操作,和顺序文件 IO(例如,IO slave activity)。如果你不使用这些特别的功能,你可以设置 Large Pool 为 0。 Large Pool 不使用 Least Recently Used(LRU)算法,所以在会话释放大的内存之前,它们都会保留在 Large Pool 里。

如果你需要了解 Large Pool 中内存分配的更多细节,可以运行

> sqlplus /nolog
SQL> connect / as sysdba
SQL> alter session set events 'immediate trace name heapdump level 32';

如果使用 SGA_TARGET,这个参数会显示为 0,但是你也可以显式设置一个最小值,MMAN 不会尝试收缩 Large Pool 到这个设置之下。

  • LOG_BUFFER

这个 SGA 内存组件是不能自动调节的,但是这项内存设定会影响 MMAN 实际可管理的内存。

  • OPEN_CURSORS

这个参数设置了一个 session 可以打开的游标数量的上限。一般来说,游标是通过 OCI 调用或者 PL/SQL 调用来打开的。

在 Oracle 9.2.0.5 之前的版本,OPEN_CURSORS 作为 PL/SQL 游标的缓存。当 PL/SQL 关闭了一个 PL/SQL 所打开的游标,它会检查是否可以使用 OPEN_CURSORS 分配的游标来缓存这个游标。这个游标并没有真正的关闭,但是可能被另外一个缓存的游标或者应用明确打开的游标所关闭和取代。如果应用使用 OCI 打开非常少的游标,但使用 PL/SQL 打开和关闭很多不同语句的游标,那么它可能仍然会有很多打开的游标。

如果一个用户显式的打开一个游标,虽然此会话已打开游标的数量达到了 OPEN_CURSORS;此时一个缓存的游标会被关闭,而显式打开仍然会成功。

参考:
Note 76684.1  Monitoring Open Cursors & Troubleshooting ORA-1000 Errors
Note 208857.1  SCRIPT - to Tune the 'SESSION_CACHED_CURSORS' and 'OPEN_CURSORS' Parameters

  • PROCESSES / SESSIONS

从 9.2.x 开始,这些进程会影响共享池的大小。在 9.2.x *享池会分配内存结构来存储每个进程或会话的动态参数设定。注意:在 32bit 数据库中,每个参数可以占用的内存结构最大为 20bytes,64bit 数据库中,每个参数是 32bytes。在 10.2.x,有超过 1300 个动态参数,所以当数据库中有很多用户时,所占用的内存会显著增加。你可以从 V$RESOURCE_LIMIT 中检查 Sessions 和 Processes 的高水位线。如果这些参数的设定值远高于高水位线信息,考虑减少参数设定来从共享池中释放一些内存。

  • SESSION_CACHED_CURSORS

当游标关闭时,Oracle 将会话与库缓存状态的所有联系分离开。如果没有其它的会话打开了相同的游标,库缓存对象和它的堆就会被 unpin, 并且可以做 LRU 操作。参数 SESSION_CACHED_CURSORS 控制“软”关闭的游标数量,就像缓存的 PL/SQL 游标一样。

SESSION_CACHED_CURSORS 游标不是 open_cursors 统计数据的一部分;它是一个独立列表。不是真正的关闭,而是 Oracle 将游标放在一个会话私有的 LRU 列表里,使游标可以在下次解析时可用。如果用户执行一个新的语句,它首先搜索 Session Cached Cursor 列表,如果找到,就利用它。

这个参数最初的设想是用于 Oracle FORMS 应用。为了并行化 FORMS 开发,客户经常开发独立的 form 并且在 form 之间切换。FORMS 行为是要在切换到新的 form 之前关闭前面 form 的所有的游标。如果应用打开的游标是针对同一个语句的,这个参数允许 Oracle 来”缓存”关闭的游标并且重用他们。

参数设置的高的话会增加库缓存内存的数量。(通过视图 V$SGASTAT 来监控)

在 9.2.0.5 以上, 这个参数也被重载用于控制 PL/SQL 缓存的游标的数量。之前 PL/SQL 缓存游标数量是由 OPEN_CURSORS 控制的。

参考:
Note 270097.1 ORA-4031 and Very Large Library Cache in Oracle 9.2 with Session_cached_cursors set. Library Cache Pin/Lock Pile Up hangs the application 
Note 274496.1 ORA-7445 and ORA-4031 in 9.2.0.5 and 10g if SESSION_CACHED_CURSORS is used

  • SGA_TARGET

如果设置了这个参数,MMAN 进程会尝试增长和收缩自动调节的内存组件。有趣的是,在 10.2 如果你在 spfile 中明确的设置 SGA_TARGET 高于 SGA_MAX_SIZE 设置值,那么下一次启动会忽略之前设置的 SGA_MAX_SIZE,设置它等于新的 SGA_TARGET 值。这与 11g 中的行为不同。

  • SHARED_POOL_SIZE

如果使用 SGA_TARGET,这个参数默认是 0,但是 MMAN 尝试收缩共享池时,如果这个参数有一个显式的设置,那么这个设置会作为最小值。在 9i 和 10g 中,更多的 SGA 固定内存结构被移到了共享池中。这意味着当从 Oracle 7,Oracle 8,Oracle 8i 升级上来时,你必须为 9i 和 10g 共享池所需的内存执行额外的调优分析。在 9i 及更高的版本,Oracle 还使用了一个新的子池特性。由于应用会以不同方式利用内存,这可能需要额外的调优分析。在一些情况下,共享池中出现过多的子池,可能导致一个子池过度利用并带来 ora-4031 错误。

参考:

Note 270935.1 Shared pool sizing in 10g

如果你需要查看共享池中内存如何分配的更多细节,你可以运行

> sqlplus /nolog
SQL> connect / as sysdba
SQL> alter session set events 'immediate trace name heapdump level 2';

注意:不推荐在业务高峰运行 heapdump trace,这会影响性能。

  • SHARED_POOL_RESERVED_SIZE

这个参数默认 是SHARED_POOL_SIZE的5%。当使用 SGA_TARGET 时,这个会随着共享池组件的自动增长和减少进行调节。如果你看到有持续发生的 ORA-4031 错误指出内存请求失败大于 4000byte,那么这个 5% 的默认值可能对你的应用环境来说就不够了。你可以修改隐藏参数 _shared_pool_reserved_pct 到 10。这使得保留区域利用共享池的 10%。例如

SQL> alter system set "_shared_pool_reserved_pct"=10 scope=spfile;

或者添加到 init 文件

"_shared_pool_reserved_pct"=10

  • STATISTICS_LEVEL

关于统计数据的追踪,在 10g 有额外的内存结构。这个参数控制数据库中所有的主要的统计数据收集和建议,并且设置数据库的统计数据收集级别。这个参数可以设置成 BASIC,TYPICAL 或者 ALL。

默认设置是 TYPICAL,它会给共享池增大压力,除非你调节共享池来适应数据库中进行的分析动作。在一些性能调节案例中,必须设置 STATISTICS_LEVEL 为 ALL。相对其它的设置,这会使用共享池中更多的内存,所以如果共享池没有调节到能处理额外内存需求的话,使用ALL可能导致 ORA-4031 错误。

在 9i 和 10g 中已知的一些 Bug 中,绕开方案是设置 STATISTICS_LEVEL 为 BASIC。这会使用最少的共享池内存,但是你放弃了自我调节的功能(内存,建议器,对象统计数据管理,等等)。

  • STREAMS_POOL_SIZE

这是 10g 中的新内存池。设计它的目的是要减轻有关的 Streams 操作对共享池带来的内存压力。通过 RDA 检查这个参数的大小设置。

如果在 10gR2 中使用 SGA_TARGET,这个参数会被自动调节,并且会呈现为 0。你可以在 10gR2 中给它显式设置一个最小值,MMAN 不会尝试收缩 Streams 池到小于这个设置。

如果你需要了解 Streams Pool 中内存分配的更多细节,可以运行

> sqlplus /nolog
SQL> connect / as sysdba
SQL> alter session set events 'immediate trace name heapdump level 64';

另外也检查一下跟共享服务器使用有关的设置(MTS_SERVERS,MTS_DISPATCHERS 等等)。如果这些参数显示已经配置了共享服务器,你不应该看到在共享池中有跟共享服务器有关的内存结构。

注意:上面列出来的参数中的一部分仅当使用 SGA_TARGET 时才有效。请一定要调查一下 MMAN 可以用来自动增长或者收缩的内存组件的可用内存实际有多少。

我们应该查看 RDA 中的哪些信息来帮助诊断 4031 错误?

检查 RDA 报告是因为在一个报告中包含了很多“拼图”。除非问题是简单的因为内存组件未配置或者太小,我们经常需要其它诊断信息来找到根本原因:

在'Overview','System Information'中,检查这个服务器上CPU的数量。CPU 的数量能够帮助确认共享池中使用的子池的数量。例如

ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

在'Overview','Database Information'中,查看版本信息(V$VERSION)

ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

在'RDBMS','Database Parameters'中,查看如上所述的适当的参数。使用最新版本的 RDA 报告,隐藏参数的设置也被包含在这个部分里。你应该查看如下设置'_PX_use_large_pool','_kghdsidx_count','_large_pool_min_alloc','_library_cache_advice','_shared_pool_reserved_pct','_shared_pool_reserved_min_alloc','_4031_dump_bitvec','_4031_max_dumps','_4031_dump_interval','_4031_sga_dump_interval' ,'_4031_sga_max_dumps'。

ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

在'RDBMS','V$RESOURCE_LIMIT'中,查看'processes','sessions'的高水位线信息。如果 PROCESSES 和 SESSIONS 的设置远高于高水位线信息。降低这些设置可以帮助减少一些永久内存结构分配。在 RAC 环境中,'ges*'参数的设置也非常重要。有一些 RAC/ORA-04031 Bug 是关于'ges*'参数的。

ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

在默认的 4031 追踪文件中有哪些信息是相关的?

在 9.2.0.5 或者更高版本中,当发生 ora-4031 错误时,会生成一个 trace 文件(通过 _4031_dump_bitvec 控制)。在 9.2.x,默认是 6639615 = 0x654fff , 含义是:
    0x0004fff: 除了subheaps & top sga heap w/ contents 之外,启用所有的 dump
    0x0050000: 进程 dump 之间间隔 5 分钟
    0x0600000: 在 sga heap dumps 之间间隔 60 分钟 (6 x 10)

在 10g,默认是 20479 = 0x004fff
   0x0004fff: 除了 subheaps & top sga heap w/ contents 之外,启用所有的 dump

还额外添加了其它初始化参数:

_4031_dump_interval (default 300) -  在 4031 诊断 dump 之间的最小时间间隔,单位是秒。
_4031_sga_dump_interval (default 3600) - SGA heap dump 之间的最小时间间隔。

注意:这些参数中任意一个设置为 0 意味着所有的错误都会生成一个 trace 文件。如果 ORA-04031 错误在一个短时间内频繁发生,则可能由于太多的 trace 文件生成,导致数据库挂起。
 
_4031_max_dumps (default 100) - 对每个进程能够生成的 dump 的数量设限。0 会关闭 4031dump。
_4031_sga_max_dumps (default 10) - 对每个实例能够生成的 SGA dump 的数量设限。0 会关闭 SGA dump。

确保检查头信息并且确认日期信息与错误报告一致。在 trace 文件的头信息之后,你会看到类似如下的信息。

*** SESSION ID:(242.24755) 2006-08-29 08:55:15.765 
================================= 
Begin 4031 Diagnostic Information 
================================= 
The following information assists Oracle in diagnosing 
causes of ORA-4031 errors. This trace may be disabled 
by setting the init.ora parameter _4031_dump_bitvec = 0 
====================================== 
Allocation Request Summary Information 
====================================== 
Current information setting: 00654fff 
Dump Interval=300 seconds SGA Heap Dump Interval=3600 seconds 
Last Dump Time=08/29/2006 08:55:14 
Allocation request for: optdef : apanlg    <<<< request for memeory
                                             structure (related to 
                                             inlist and the CBO)
Heap: 44b5c89b8, size: 96   <<<****************************************************** 
****************************************************** 
HEAP DUMP heap name="sga heap" desc=380000030 
extent sz=0xfe0 alt=200 het=32767 rec=9 flg=-126 opc=0 
parent=0 owner=0 nex=0 xsz=0x1 
****************************************************** 
HEAP DUMP heap name="sql area" desc=44b5c89b8  <                                                      在"sql area"
extent sz=0x1040 alt=32767 het=32 rec=0 flg=2 opc=2 
parent=380000030 owner=44b5c8898 nex=0 xsz=0x1 
Subheap has 840329704 bytes of memory allocated

向下滚动 trace 文件,直到 Stack Trace 列表结束之后,

----- End of Call Stack Trace ----- 
=============================== 
Memory Utilization of Subpool 1     <=============================== 
Allocation Name Size 
_________________________ __________ 
"free memory " 124944864     <<<< 这是发生错误时的 "free memory" 
"miscellaneous " 57893552    <<<< 在 10gR2 之前,这是很多小内存区域的统一占位符。
"sim memory hea " 2319640 
"PL/SQL PPCODE " 0 
"KQR L SO " 56320 
"type object de " 0 
"trigger source " 0 
"errors " 0 
"PX subheap " 147016 
"trigger defini " 0 
"trigger inform " 0 
"PLS non-lib hp " 2088 
"KGLS heap " 215352 
"FileOpenBlock " 7517528 
"KQR M SO " 39976 
"PL/SQL SOURCE " 0 
"PL/SQL DIANA " 99968 
"joxlod: in phe " 0 
"db_block_hash_buckets " 9978352 
"joxs heap init " 4240 
"MTTR advisory " 697248 
"fixed allocation callback" 552 
"dictionary cache " 3229952 
"KQR L PO " 245784 
"KQR M PO " 319096 
"parameters " 0 
"partitioning d " 0 
"library cache " 18615496 
"table definiti " 0 
"sql area " 901605416   <                               这里已经分配的内存。
"pl/sql source " 0 
"transaction co " 0 
"KGK heap " 7000 
"KQR S SO " 14360 
"event statistics per sess" 12499760 
"joxlod: in ehe " 357736 
"temporary tabl " 0 
"PL/SQL MPCODE " 39392

在 trace 文件中再向下翻一点,我们看到错误发生时的 Library Cache 信息

LIBRARY CACHE STATISTICS:  (emphasis added on key areas)
namespace gets hit ratio pins hit ratio reloads invalids 
--------------  --------- --------- --------- --------- ---------- ---------- 
CRSR 4265150 0.977 496114150 0.999 155148 46115 
TABL/PRCD/TYPE 40860748 0.999 80409664 0.994 190813 0 
BODY/TYBD 52028 0.996 55986 0.920 3084 0 
TRGR 468975 0.998 468975 0.998 76 0 
INDX 54546 0.919 65318 0.867 0 0 
CLST 122885 0.992 166510 0.989 0 0 
OBJE  0 0.000 0 0.000 0 0

在 Library Cache 统计信息里,找到'hit ratio'百分比,这指示了碎片问题。目标是使得'hit ratio'尽可能的接近 100%。另外要查看 reloads 和 invalids 信息。reloads 和 invalids 很多意味着库缓存中发生了很多内存清理,可能意味着应用低效和碎片化。

在 10gR2 中,V$SGASTAT 视图比以前版本包含更多的细节。作为 10gR2 上的开始方案,可以在高峰期,每 30分钟左右运行 SGAStat.sql(来自 Note: 430473.1)中的查询,运行几个小时。比较内存条目的结果可以帮助找到哪里的分配增长了。

如果显式的设置 Heapdump 事件

alter system set events '4031 trace name HEAPDUMP level 536870914';

你会看到对内存更加详细的描述

SUBHEAP 1: desc=3800092e0 
****************************************************** 
HEAP DUMP heap name="KSFD SGA I/O b" desc=3800092e0 
extent sz=0x4258 alt=32767 het=32767 rec=9 flg=3 opc=0 
. . . 
****************************************************** 
SUBHEAP 2: desc=3a1b57a10 
****************************************************** 
HEAP DUMP heap name="PX subheap" desc=3a1b57a10 
extent sz=0xff50 alt=32767 het=32767 rec=9 flg=2 opc=0 
parent=380000030 owner=0 nex=0 xsz=0xff38 
EXTENT 0 addr=3a4342860 
Chunk 3a4342870 sz= 64904 free " " 
Chunk 3a43525f8 sz= 104 freeable "PX msg batch st" 
Chunk 3a4352660 sz= 104 freeable "PX msg batch st" 
Chunk 3a43526c8 sz= 104 freeable "PX msg batch st" 
Chunk 3a4352730 sz= 104 freeable "PX msg batch st" 
Total heap size = 65320       <FREE LISTS: 
Bucket 0 size=40 
Bucket 1 size=104 
Bucket 2 size=528 
Bucket 3 size=600 
Bucket 4 size=1112 
Bucket 5 size=1120 
Chunk 3a4342870 sz= 64904 free " " 
Total free space = 64904       <UNPINNED RECREATABLE CHUNKS (lru first): 
PERMANENT CHUNKS: 
Permanent space = 0 
******************************************************

在一些情况中,必须 dump 出 subheap 里面的额外信息。例如

     <>>

Chunk 3a0ba0480 sz= 4184 freeable "CURSOR STATS " ds=3a1a6c0d8 
. . . 
ds 3a1a6c0d8 sz= 246856 ct= 59 
39e642190 sz= 4184 
39c08c728 sz= 4184

SQL> ORADEBUG SETMYPID 
SQL> ORADEBUG DUMP HEAPDUMP_ADDR 1 15596962008  (decimal value for 3a1a6c0d8)

<>>

HEAP DUMP heap name="CURSOR STATS" desc=3a1a6c0d8 
extent sz=0x1040 alt=32767 het=32767 rec=9 flg=3 opc=0 
parent=380000030 owner=0 nex=0 xsz=0x1040 
EXTENT 0 addr=39e6421a8 
Chunk 39e6421b8 sz= 4144 free " " 
EXTENT 1 addr=39c08c740 
Chunk 39c08c750 sz= 80 freeable "kks pstat " 
. . . 
Chunk 39c08c860 sz= 336 freeable "kks cstat "

在 Statspack/AWR 报告中有哪些信息是与 4031 错误相关的?

当使用 Statspack/AWR 报告调查 4031 错误时,集中在如下几点

- time period 
- v$librarycache statistics 
- parse vs execute and parse/sec (hard vs soft parses) 
- Waits section 
- Parameter section 
- Latch contention

Database    DB Id      Instance   Inst Num  Startup Time    Release    RAC 
~~~~~~~~ ----------- ------------ -------- --------------- ----------- --- 
          1460166532 cqlwh               1 28-Nov-05 20:18  10.2.0.1.0 NO

Host Name: cqlstldb06.ceque Num CPUs: 4 Phys Memory (MB): 3,992

以及

Load Profile 
~~~~~~~~~~~~

Per Second      Per Transaction 
              --------------- --------------- 
     Parses:           132.46           31.70 
Hard parses:             0.73            0.17

Instance Efficiency Percentages (Target 100%) 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
              Library Hit %: 99.90    Soft Parse %: 99.45 
         Execute to Parse %: 42.77     Latch Hit %: 99.91 
Parse CPU to Parse Elapsd %: 97.19 % Non-Parse CPU: 93.91

Shared Pool Statistics     Begin   End 
                           ------ ------ 
           Memory Usage %:  95.54  95.50 
  % SQL with executions>1:  71.11  67.96 <% Memory for SQL w/exec>1:  64.80  64.01

要进一步的调查 Library Cache 问题,可以查看错误发生前后时段的一系列的 Statspack 报告。在 10g 中,你可以在 Snapshots 报告中找到 Library Cache 信息。点击'Performance'页面,翻到最下面。点击'Snapshots'链接,点击’ID’链接,选择一个你的数据库生成的 Snapshot。选择‘Report’页面,你会看到以 HTML 格式显示的类似于如下的信息。

ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

ORA-4031 错误故障排除与诊断[视频] (Doc ID 2016002.1)

我们如何确定是否有应用的问题导致了这个错误?

应用代码中常见的问题是

    - 没有使用绑定变量
    - 多个子游标
    - 高解析率

这种情况下你应该考虑的问题是:

1.  问题会在重启数据库后多久发生?
2.  你是否运行了 Statspack 报告或者 10g 上的 AWR?是否看到很高的硬解析数量?
3.  应用使用了绑定变量还是字面值?
4.  收集统计信息的频率如何?当你收集统计信息时,对于有新的统计数据的表,它们在库缓存中关联的对象会失效。
5.  库缓存中是否有 high version counts 的迹象?

从 Note 430473.1 中,运行SQLStats.sql脚本。

只有当你看到不寻常的高数值的时候才是一个问题。有 high version counts 的游标可能意味着在游标共享上存在问题。游标出现大的 shareable_mem 并不一定是有问题,但记得共享池的分配被限制在大约 4k。更大的分配会给保留区域带来压力,并且对 heap manager 发出多个请求(导致内部 latch 上的竞争)。

可以通过查询调查每一种可能性。

参考:
Note 232443.1 How to Identify Resource Intensive SQL for Tuning

没有使用绑定变量

下面是一个内部测试的例子,没有使用绑定变量。这个测试代码在2到3分钟之内都没有完成。

alter system flush shared_pool;

declare 
type rc is ref cursor; 
l_rc rc; 
l_dummy all_objects.object_name%type; 
l_start number default dbms_utility.get_time; 
begin 
for i in 1 .. 1000 
loop 
open l_rc for 
'select object_name 
from all_objects 
where object_id = ' || i; 
fetch l_rc into l_dummy; 
close l_rc; 
end loop; 
dbms_output.put_line 
( round( (dbms_utility.get_time-l_start)/100, 2 ) || 
' seconds...' ); 
end; 
/

简单的将测试代码改为只用一个绑定变量,性能奇迹般的改变了,只用了2到3秒就完成了

alter system flush shared_pool;

declare 
type rc is ref cursor; 
l_rc rc; 
l_dummy all_objects.object_name%type; 
l_start number default dbms_utility.get_time; 
begin 
for i in 1 .. 1000 
loop 
open l_rc for 
'select object_name 
from all_objects 
where object_id = :x' using i; 
fetch l_rc into l_dummy; 
close l_rc; 
end loop; 
dbms_output.put_line 
( round( (dbms_utility.get_time-l_start)/100, 2 ) || 
' seconds...' ); 
end; 
/

不使用绑定变量会导致共享池/库缓存的过度使用。

当你发现问题与高硬解析数量有关时,可以这样调查。

<< from Statspack report>>

Load Profile 
~~~~~~~~~~~~ 
                   Per Second      Per Transaction 
                   --------------- --------------- 
Redo size:            3,092,800.46        2,563.60 
Logical reads:          314,615.77          260.78 
Block changes:           18,384.93           15.24 
Physical reads:           7,497.42            6.21 
Physical writes:          1,698.45            1.41 
User calls:               4,922.77            4.08 
Parses:                   8,245.52            6.83 
Hard parses:                141.85            0.12    <Sorts:                   10,794.93            8.95 
Logons:                       2.72            0.00 
Executes:                22,421.54           18.59 
Transactions:             1,206.43

% Blocks changed per Read: 5.84 Recursive Call %: 92.53 
Rollback per transaction %: 2.17 Rows per Sort: 5.23

从数据库的角度,你可以使用 CURSOR_SHARING=SIMILAR|FORCE,字面值会在后台被绑定变量所取代。FORCE 和 SIMILAR 几乎是相同的,但是 SIMILAR 还会考虑优化器计划。CURSOR_SHARING 还有其它的性能影响,所以你需要在改变这个参数之前对环境进行测试。CURSOR_SHARING 是一个动态参数,但是在共享池中的作用不是立刻生效的。你可以 flush 这个池或者重启数据库,这样可以开始更好的利用内存。

多个子游标

每个子游标都会在共享池中分配空间。在一些案例中,过去的已知的 Bug,创建了过多的子游标,分配的内存超过了期望的行为。

(Version 10g) 
select sa.sql_text,sa.version_count,ss.*
from v$sqlarea sa,v$sql_shared_cursor ss 
where sa.address=ss.address 
and sa.version_count > 50 
order by sa.version_count ;

(Version 8,9) 
select sa.sql_text,sa.version_count ,ss.*
from v$sqlarea sa,v$sql_shared_cursor ss 
where sa.address=ss.kglhdpar 
and sa.version_count > 50 
order by sa.version_count ;

这个查询会显示拥有超过 50 个的子游标,标记为‘Y’的列指出了生成子游标的原因。输出中标记为‘N’的列可以忽略。

警告:
Note 403616.1 Many Child Cursors create in 10.2.0.3 on Windows and Linux

注意:V$SQL_SHARED_CURSOR视图中包含’Y’和’N’列。

Note 430473.1 提供一个脚本更好的解析了这个视图的信息。

高解析率

重要的是找出什么导致了高解析调用:

- 使用动态 PL/SQL
- 在高负载阶段执行 DDL 语句。每次 DDL 语句执行,都会导致所有引用了这个对象的语句失效。下次执行引用了这个对象的 sql 语句时,则不得不重新解析并加载到共享池中。

会导致这种情形的典型操作是:

- Grant/revoke command 
- Alter view 
- Alter package | procedure 
- Analyze table |index 
- DBMS_STATS
- Truncate table 
- Alter index 
- Alter table move

如果一个 ora-04031 错误与高解析率有关,你也会看到 library cache latch 上的 latch 竞争,在 Statspack 或者 AWR 报告中的库缓存统计信息中,也会看到很多的 invalidations 和 reloads。

Note 1012047.6 How To Pin Objects in Your Shared Pool
Note 69925.1 PINNING ORACLE APPLICATIONS OBJECTS INTO THE SHARED POOL

参考

NOTE:34579.1 - WAITEVENT: "library cache pin" Reference Note
NOTE:443746.1 - Automatic Memory Management (AMM) on 11g & 12c

NOTE:1269139.1 - SGA Re-Sizes Occurring Despite AMM/ASMM Being Disabled (MEMORY_TARGET/SGA_TARGET=0)
NOTE:459694.1 - Procwatcher: Script to Monitor and Examine Oracle DB and Clusterware Processes
NOTE:377143.1 - How to Check what Automatic Statistics Collections are Scheduled on Oracle 10g
BUG:4994956 - NUMBER OF CONFIGURED SHARED POOL SUBPOOLS IS NOT CORRECT
NOTE:1381442.1 - How to use the ORA-4031 Troubleshooting Tool on MOS
NOTE:69925.1 - Pinning Oracle E-Business Suite Objects Into The Shared Pool
NOTE:1355030.1 - How To Troubleshoot ORA-4031's and Shared Pool Issues With Procwatcher
NOTE:208857.1 - SCRIPT - to Set the 'SESSION_CACHED_CURSORS' and 'OPEN_CURSORS' Parameters Based on Usage
NOTE:208918.1 - SCRIPT - to Gauge the Impact of the SESSION_CACHED_CURSORS Parameter

NOTE:270097.1 - ORA-4031 and Very Large Library Cache in Oracle 9.2 with Session_cached_cursors set.
NOTE:115656.1 - Legacy: Wait Scenarios Regarding 'library cache pin' and 'library cache load lock'
NOTE:430473.1 - ORA-4031 Common Analysis/Diagnostic Scripts [Video]
NOTE:232443.1 - How to Identify Resource Intensive SQL ("TOP SQL")
NOTE:146599.1 - Diagnosing and Resolving Error ORA-04031 on the Shared Pool or Other Memory Pools [Video]
NOTE:1012047.6 - How To Pin Objects in the Shared Pool
NOTE:270935.1 - Shared pool sizing
NOTE:778.1 - Troubleshooting Video Issues in MOS
NOTE:4031.1 - OERR: ORA-4031 "unable to allocate %s bytes of shared memory ("%s","%s","%s")"
NOTE:287059.1 - Library Cache Pin/Lock Pile Up in Pre-10g versions
NOTE:76684.1 - Monitoring Open Cursors & Troubleshooting ORA-1000 Errors

BUG:3352753 - ORA-600 [KCBLIBR_1] FOLLOWED IMMEDIATELY BY ORA-4031
NOTE:274496.1 - ora-7445 and ora-4031 in 9.2.0.5 and 10g if SESSION_CACHED_CURSORS is used
NOTE:403616.1 - Many Child Cursors create in 10.2.0.3 on Windows and Linux

BUG:3663344 - V$SGASTAT SHOWS ENORMOUS VALUE FOR 'TRANSACTION CO' MEMORY AREA
NOTE:947152.1 - How To Determine Granule Size

上一篇:POJ 3114 Countries in War(强连通)(缩点)(最短路)


下一篇:qt介绍04——Qt5.5.0(32位)源码裁剪