buffer cache 和shared pool详解(之五,问题诊断总结)

【深入解析--eygle】 学习笔记

1.2.7 诊断和解决ORA-04031 错误

Shared  Pool的主要问题在根本上只有一个,就是碎片过多带来的性能影响

1.2.7.1 什么是ORA-04031错误

当尝试在共享池分配大块的连续内存失败(很多时候是由于碎片过多,而并非真是内存不足)时,Oracle首先清除共享池中当前没使用的所有对象,使空闲内存块合并。如果仍然没有足够大的单块内存可以满足需要,就会产生ORA-04031错误。

如下一段伪代码来描述04031错误的产生:

Scan free lists      --扫描Free Lists

if (request size of RESERVED Pool size)    --如果请求RESERVED POOL空间

scan reserved list          --扫描保留列表

if (chunk found)           --如果发现满足条件的内存块

check chunk size and perhaps truncate  --检查大小,可能需要分割

return               --返回

do LRU operation for n objects       --如果并非请求RESERVED POOL或不能发现足够内存

scan free lists          --则转而执行LRU操作,释放内存,重新扫描

if  (request  sizes exceeds  reserved  pool min  alloc) 
– 如果请求大于

_shared_pool_reserved_min_alloc

scan reserved list            --扫描保留列表

if (chunk found)              --如果发现满足条件的内存块

check chunk size and perhaps truncate    --检查大小,可能需要分割

return               --在Freelist或reservedlist找到则成功返回

signal ORA-4031 error              --否则报告ORA-04031错误。

[[email protected] ~]$ oerr ora 4031

04031, 00000, "unable to allocate %s bytes ofshared memory(\"%s\",\"%s\",\"%s\",\"%s\")"

// *Cause: More shared memory is needed than was allocated in the shared

//         pool or Streams pool.

// *Action: If the shared pool is out of memory,either use the

//         DBMS_SHARED_POOL package to pin large packages,

//         reduce your use of shared memory, or increase the amount of

//         available shared memory by increasing the value of the

//         initialization parameters SHARED_POOL_RESERVED_SIZE and

//         SHARED_POOL_SIZE.

//         If the large pool is out of memory, increase the initialization

//         parameter LARGE_POOL_SIZE.

//         If the error is issued from an Oracle Streams or XStream process,

//         increase the initialization parameter STREAMS_POOL_SIZE or increase

//         the capture or apply parameter MAX_SGA_SIZE.

[[email protected] ~]$

1.2.7.2 绑定变量和cursor_sharing

如果SHARED_POOL_SIZE设置得足够大,又可以排除Bug的因素,那么大多数的ORA-04031错误都是由共享池中的大量的SQL代码等导致过多内存碎片引起的

可能的主要原因有:

(1)SQL没有足够的共享;

(2)大量不必要的解析调用;

(3)没有使用绑定变量。

 

实际上说,应用的编写和调整始终是最重要的内容,Shared  Pool的调整根本上要从应用入手。根本上,使用绑定变量可以充分降低Shared Pool和Library Cache的Latch竞争,从而提高性能。

反复的SQL硬解析不仅会消耗大量的CPU资源,也会占用更多的内存,严重影响数据库的性能,而使用绑定变量则可以使SQL充分共享,实现SQL的软解析,提高系统性能。

(1)创建表病记录解析统计记录:

15:46:52[email protected]>create table felix (id number);

Table created.

15:47:48 [email protected] SQL>SELECT NAME,VALUE FROMV$MYSTAT A,V$STATNAME B WHERE A.STATISTIC#=B.STATISTIC# AND NAME LIKE ‘parse%‘;

NAME                                           VALUE

----------------------------------------------------

parse time cpu                                     28

parse time elapsed                                 82

parse count (total)                               294

parse count (hard)                                180

parse count (failures)                              0

parse count (describe)                              0

6 rows selected.

15:54:32 [email protected] SQL>

(2)进行循环插入数据,以下代码并未使用绑定变量:

felix SQL> begin

for i in 1..10 loop

execute immediate ‘insert into felixvalues(‘||i||‘)‘;

end loop;

commit;

end;

/

PL/SQL procedure successfully completed.

(3)完成之后检查统计信息,注意硬解析次数增加了10次,也就是说每次INSERT操作都需要进行一次独立的解析:

16:02:22 [email protected] SQL>SELECT NAME,VALUE FROMV$MYSTAT A,V$STATNAME B WHERE A.STATISTIC#=B.STATISTIC# AND NAME LIKE ‘parse%‘;

NAME                                           VALUE

----------------------------------------------------

parse time cpu                                     32

parse time elapsed                                 89

parse count (total)                               336

parse count (hard)                              
 190

parse count (failures)                              1

parse count (describe)                              0

6 rows selected.

16:02:29 [email protected] SQL>

查询V$SQLAREA视图,可以找到这些不能共享的SQL,注 意 每 条SQL都只执行了一次,这些SQL不仅解析要消耗密集的SQL资源,也要占用共享内存存储这些不同的SQL代码:

SELECT sql_text, version_count, parse_calls, executions

FROM v$sqlarea

WHERE sql_text LIKE ‘insert into felix%‘;

SQL_TEXT                           VERSION_COUNTPARSE_CALLS EXECUTIONS

-------------------------------- ------------------------ ----------

insert into felix values(9)         1              1               1

insert into felix values(5)         1             1               1

insert into felix values(8)         1              1               1

insert into felix values(1)         1              1               1

insert into felix values(4)         1              1               1

insert into felix values(6)         1              1               1

insert into felix values(3)         1              1               1

insert into felix values(7)         1              1               1

insert into felix values(2)         1              1               1

insert into felix values(10)        1              1               1

10 rows selected.

重构测试表,进行第二次测试:

[email protected] SQL>drop  table felix purge;

[email protected] SQL>create table felix (id number);

begin

for i in1..10 loop

executeimmediate ‘insert into felix values(:v1)‘ using i;

end loop;

commit;

end;

/

对于该SQL,在共享池中只存在一份,解析一次,执行10次,这就是绑定变量的优势所在:

SELECT sql_text, version_count, parse_calls,executions

FROMv$sqlarea

WHEREsql_text LIKE ‘insert into felix%‘;

SQL_TEXT                          VERSION_COUNT PARSE_CALLSEXECUTIONS

-------------------------------- ------------------------ ----------

insert into felix values(:v1)         1              1               1

在应用程序开发的过程中,都应该优先考虑使用绑定变量(在JAVA应用中可以使用PreparedStatement进行变量绑定),但是如果应用没有很好地使用绑定变量,那么Oracle从8.1.6开始提供了一个新的初始化参数用以在Server
端进行强制变量绑定,这个参数就是cursor_sharing。最初这个参数有两个可选设置:exact和force。

缺省值是exact,表示精确匹配;force表示在Server端执行强制绑定。在8i的版本里使用这个参数对某些应用可以带来极大的性能提高,但是同时也存在一些副作用,比如优化器无法生成精确的执行计划,SQL执行计划发生改变等(所以如果启用cursor_sharing参数时,一定确认用户的应用在此模式下经过充分的测试)。

从Oracle 9i开始,Oracle引入了绑定变量Peeking的机制,SQL在第一次执行时,首先在Session的PGA中使用具体值生成精确的执行计划,以期可以提高执行计划的准确性,然而Peeking的方式只在第一次硬解析时生效,所以仍然可能存在问题,导致后续的SQL错误的执行;同时,在Oracle 
9i中,cursor_sharing参数有了第3个选项:similar。该参数指定Oracle在存在柱状图信息时,对于不同的变量值,重新解析,从而可以利用柱状图更为精确地制定SQL执行计划。也即当存在柱状图信息时,similar的表现和exact相同;当柱状图信息不存在时,similar的表现和force相同。

除了Bug之外,在正常情况下,由于Similar的判断机制,可能也会导致SQL无法共享。在收集了柱状图(Hisogram)信息之后,如果SQL未使用绑定变量,当SQL使用具备柱状图信息的Column时,数据库会认为SQL传递过来的每个常量都是不可靠的,需要为每个SQL生成一个Cursor,这种情况被称为UNSAFE 
BINDS。大量的Version_Count可能会导致数据库产生大量的cursor: pin S wait on X等待。解决这类问题,可以设置CURSOR_SHARING为Force或者删除相应字段上的柱状图信息。

1.2.7.3 使用Flush Shared Pool缓解共享池问题

一种应急处理方法,强制刷新共享池。

alter system flushshared_pool;

刷新共享池可以帮助合并碎片(smallchunks), 强 制 老 化SQL,释放共享池,但是这通常是不推荐的做法,这是因为:

(1)Flush Shared Pool会导致当前未使用的cursor被清除出共享池,如果这些SQL随后需要执行,那么数据库将经历大量的硬解析,系统将会经历严重的CPU争用,数据库将会产生激烈的Latch竞争。

(2)如果应用没有使用绑定变量,大量类似SQL不停执行,那么Flush Shared Pool可能只能带来短暂的改善,数据库很快就会回到原来的状态。

(3)如果Shared Pool很大,并且系统非常繁忙,刷新Shared Pool可能会导致系统挂起,对于类似系统尽量在系统空闲时进行

1.2.7.4 SHARED_POOL_RESERVED_SIZE参数的设置及作用

shared_pool_reserved_size,该参数指定了保留的共享池空间,用于满足将来的大的连续的共享池空间请求。当共享池出现过多碎片,请求大块空间会导致Oracle
大范围的查找并释放共享池内存来满足请求,由此可能会带来较为严重的性能下降,设置合适的shared_pool_reserved_size参数,结合shared_pool_reserved_min_alloc参数可以用来避免由此导致的性能下降。

这个参数理想值应该大到足以满足任何对RESERVED  LIST的内存请求,而无需数据库从共享池中刷新对象。这个参数的缺省值是shared_pool_size
的5%,通常这个参数的建议值为shared_pool_size参数的10%~20%大小,最大不得超过shared_pool_size的50%。

shared_pool_reserved_min_alloc这个参数的值控制保留内存的使用和分配。如果一个足够尺寸的大块内存请求在共享池空闲列表中没能找到,内存就从保留列表(RESERVED  LIST)中分配一块比这个值大的空间。

如果你的系统经常出现的ORA-04031错误都是请求大于4400的内存块,那么就可能需要增加shared_pool_reserved_size参数设置。

而如果主要的引发LRU合并、老化并出现04031错误的内存请求在4100~4400byte之间,那么降低_shared_pool_reserved_min_alloc
同时适当增大SHARED_POOL_RESERVED_SIZE参数值通常会有所帮助。设置_shared_pool_reserved_min_alloc=4100可以增加Shared Pool成功满足请求的概率。需要注意的是,这个参数的修改应当结合Shared  Pool Size和Shared Pool
Reserved Size的修改。设置_shared_pool_reserved_min_alloc=4100是经过证明的可靠方式,不建议设置更低。

查询v$shared_pool_reserved视图可以用于判断共享池问题的引发原因:

16:26:38 [email protected] SQL>S SELECT free_space,

avg_free_size,

used_space,

avg_used_size,

request_failures,

last_failure_size

FROMv$shared_pool_reserved;

FREE_SPACE AVG_FREE_SIZE USED_SPACE AVG_USED_SIZEREQUEST_FAILURES LAST_FAILURE_SIZE

---------- ------------- ---------- ----------------------------- -----------------

7255512    196094.919    8155392        220416                0                 0

17:04:04 [email protected] SQL>

如果request_failures>0
并且last_failure_size>shared_pool_reserved_min_alloc,那么ORA-04031
错误就可能是因为共享池保留空间缺少连续空间所致。要解决这个问题,可以考虑加大shared_pool_reserved_min_alloc
来降低缓冲进共享池保留空间的对象数目,并增大shared_pool_reserved_size和shared_pool_size来加大共享池保留空间的可用内存。

如果request_failures>0
并且last_failure_size<shared_pool_reserved_min_alloc 或者request_failures=0并且last_failure_size<shared_pool_reserved_min_alloc,那么是因为在库高速缓冲缺少连续空间导致ORA-04031错误。对于这一类情况应该考虑降低shared_pool_reserved_min_alloc以放入更多的对象到共享池保留空间中并且加大shared_pool_size。

1.2.7.5 其他

此外,某些特定的SQL,较大的指针或者大的Package都可能导致ORA-04031错误。在很多ERP软件中,这样的情况非常常见。在这种情况下,可以考虑把这个大的对象Pin
到共享池中,减少其动态请求、分配所带来的负担

使用dbms_shared_pool.keep
系统包可以把这些对象pin 到内存中,最常见的SYS.STANDARD、SYS.DBMS_STANDARD等都是常见的候选对象。

注意:要使用DBMS_SHARED_POOL系统包,首先需要运行dbmspool.sql脚本,该脚本会自动调用prvtpool.plb
脚本创建所需对象。

引发ORA-04031 错误的因素还有很多,通过设置相关参数如session_cached_cursors、cursor_space_for_time等也可以解决一些性能问题并带来针对性的性能改善,这里不再过多讨论。

1.2.8 Library Cache Pin 及Library Cache Lock分析

Oracle使用两种数据结构来进行Library Cache的并发访问控制:lock 和 pin

Lock可以被认为是解析锁,而Pin则可以被认为是以读取或改变对象内容为目的所加的短时锁。之所以将Library  Cache Object对象分开,使用多个锁定来保护,其中的一个重要目的就是为了提高并发。

Lock比Pin具有更高的级别。Lock在对象handle上获得,在pin一个对象之前,必须首先获得该handle的锁定。Handle可以理解为Libray  Cache对象的Buffer  Header,其中包含了库缓存对象的名称、标记、指向具体对象的内存地址指针等信息。

再次引用一下前文曾经提到的图表,通过下图我们可以清晰的看到Object Handles和Heaps的关系:

锁定主要有三种模式:  Null,share,Exclusive。在读取访问对象时,通常需要获取Null(空)模式以及share(共享)模式的锁定。在修改对象时,需要获得Exclusive(排他)锁定Library
Cache Lock根本作用就是控制多个Oracle客户端对同一个Library  Cache对象的并发访问,通过对Library Cache Object Hadle上加锁来防止非兼容的访问。

常见的使用或保护包括:

1.  一个客户端防止其他客户端访问同一对象

2.  一个客户端可以通过锁定维持相对长时间的依赖性(例如,防止其他客户端修改对象)

3.  当在Library Cache中定位对象时也需要获得这个锁定

在锁定了Library Cache对象以后,一个进程在访问之前必须pin该对象。同样pin有三种模式,Null,shared和exclusive。只读模式时获得共享pin,修改模式获得排他pin。通常我们访问、执行过程、Package时获得的都是共享pin,如果排他pin被持有,那么数据库此时就要产生等待。

为了实现更好的性能,从Oracle10gR2开始,Library Cache Pin已经逐渐被互斥机制(Mutex)所取代,在Oracle Database 11g中,这个变化就更为明显。

1.2.8.1 LIBRARY CACHE PIN等待事件

library cache pin是用来管理library cache的并发访问的,pin一个Object会引起相应的heap被载入内存中(如果此前没有被加载),pins可以在Null、Share、Exclusive这3个模式下获得,可以认为pin是一种特定形式的锁。

当library cache pin等待事件出现时,通常说明该pin被其他用户已非兼容模式持有。library cache  pin的等待时间为3秒钟,其中有1秒钟用于PMON后台进程,即在取得pin之前最多等待3秒钟,否则就超时。

ibrary cache pin的参数有P1(KGL Handle Address)、P2(Pin Address)和P3(Encoded
Mode & Namespace), 常用的主要是P1和P2

library cache pin通常是发生在编译或重新编译PL/SQL、VIEW、TYPES等Object时。

当Object变得无效时,Oracle会在第一次访问此Object时试图去重新编译它,如果此时其他session已经把此Object  pin到library 
cache 中,就会出现问题,特别时当有大量的活动session并且存在较复杂的dependence时。在某种情况下,重新编译Object可能会花几个小时时间,从而阻塞其他试图去访问此Object的进程。

recompile过程包含以下步骤:

(1)存储过程的library  cache  object以排他模式被锁定,这个锁定是在handle上获得的。Exclusive
锁定可以防止其他用户执行同样的操作,同时防止其他用户创建新的引用此过程的对象。

(2)以Shared模式pin该对象,以执行安全和错误检查。

(3)共享pin被释放,重新以排他模式pin该对象,执行重编译。

(4)使所有依赖该过程的对象失效。

(5)释放Exclusive Lock和Exclusive Pin。

从Oracle 10g开始,以上测试将不会看到同样的效果,这是因为Oracle 10g对于对象编译与重建做出了增强。注意当重新replace一个过程时,Oracle会首先执行检查,如果代码前后完全相同,则replace工作并不会真正进行(因为没有变化),对象的LAST_DDL_TIME不会改变,这就意味着Latch的竞争可以减少。

对于version_count过高的问题,可以查询V$SQL_SHARED_CURSOR视图,这个视图会给出SQL不能共享的具体原因,如果是正常因素导致的,相应的字段会被标记为“Y”;对于异常的情况(如本案例),查询结果可能显示的都是“N”,这就表明Oracle认为这种行为是正常的,在当前系统设置下,这些SQL不应该被共享,那么可以判断是某个参数设置引起的。和SQL共享关系最大的一个初始化参数就是cursor_sharing,在这个案例中cursor_sharing参数被设置为similar,正是这个设置导致了大量子指针不能共享。

1.2.9  V$SQL与V$SQLAREA视图

在前面提到过一个经常被问及的问题:V$SQL与V$SQLAREA两个视图有什么不同?所以有这样一个问题是因为这两个视图在结构上非常相似。

V$SQLAREA和V$SQL两个视图的不同之处在于,V$SQL中为每一条SQL保留一个条目,而V$SQLAREA中根据SQL_TEXT进行GROUP  BY,通过version_count计算子指针的个数。

buffer cache 和shared pool详解(之五,问题诊断总结)

时间: 2024-10-26 12:02:25

buffer cache 和shared pool详解(之五,问题诊断总结)的相关文章

buffer cache 和shared pool 详解(之三,shared pool原理)

[深入解析--eygle] 学习笔记 1.2 shared pool原理 Shared Pool是Oracle SGA设置中最复杂也是最重要的一部分内容,Oracle通过Shared Pool来实现SQL共享.减少代码硬解析等,从而提高数据库的性能.在某些版本中,如果设置不当,Shared Pool可能会极大影响数据库的正常运行. 在Oracle 7之前,Shared Pool并不存在,每个Oracle连接都有一个独立的Server进程与之相关联,Server进程负责解析和优化所有SQL和PL/

buffer pool和shared pool详解(之四,重要视图、以及转储)

1.2.5  X$KSMSP视图 Shared  Pool 的空间分配和使用情况,可以通过一个内部视图来观察,这个视图就是X$KSMSP. X$KSMSP的名称含义为: [K]ernal [S]torage [M]emory Management [S]GA Hea[P]其中每一行都代表着Shared Pool中的一个Chunk.以下是x$ksmsp的结构: 12:03:45 [email protected] SQL>desc x$ksmsp Name                     

buffer pool 和shared pool 详解(一)

[深入解析--eygle]学习笔记 1.1 buffer pool原理 Buffer Cache是Oracle SGA中一个重要部分,通常的数据访问和修改都需要通过BufferCache来完成.当一个进程需要访问数据时,首先需要确定数据在内存中是否存在,如果数据在Buffer中存在,则需要根据数据的状态来判断是否可以直接访问还是需要构造一致性读取:如果数据在Buffer中不存在,则需要在Buffer Cache中寻找足够的空间以装载需要的数据,如果Buffer  Cache中找不到足够的内存空间

shared pool 和buffer pool 详解(之二, Cache Buffers LRU Chain、Cache Buffers LRU Chain闩锁竞争与解决)

[深入解析--eygle]学习笔记 1.1.2  Cache BuffersLRU Chain闩锁竞争与解决 当用户进程需要读数据到Buffer Cache时或Cache Buffer根据LRU算法进行管理等,就不可避免的要扫描LRU  List获取可用Buffer或更改Buffer状态,我们知道,Oracle的Buffer Cache是共享内存,可以为众多并发进程并发访问,所以在搜索的过程中必须获取Latch(Latch是Oracle的一种串行锁机制,用于保护共享内存结构),锁定内存结构,防止

深入Golang之sync.Pool详解

我们通常用golang来构建高并发场景下的应用,但是由于golang内建的GC机制会影响应用的性能,为了减少GC,golang提供了对象重用的机制,也就是sync.Pool对象池. sync.Pool是可伸缩的,并发安全的.其大小仅受限于内存的大小,可以被看作是一个存放可重用对象的值的容器. 设计的目的是存放已经分配的但是暂时不用的对象,在需要用到的时候直接从pool中取. 任何存放区其中的值可以在任何时候被删除而不通知,在高负载下可以动态的扩容,在不活跃时对象池会收缩. sync.Pool首先

Git详解之五 分布式Git

来自:http://www.open-open.com/lib/view/open1328070090108.html 分布式 Git 为了便于项目中的所有开发者分享代码,我们准备好了一台服务器存放远程 Git 仓库.经过前面几章的学习,我们已经学会了一些基本的本地工作流程中所需用到的命令.接下来,我们要学习下如何利用 Git 来组织和完成分布式工作流程. 特别是,当作为项目贡献者时,我们该怎么做才能方便维护者采纳更新:或者作为项目维护者时,又该怎样有效管理大量贡献者的提交. 5.1  分布式工

OpenGL ES 3.0之Fragment buffer objects(FBO)详解(一)

片段操作图 这篇文章将介绍从写入帧缓冲和读取帧缓冲的方式. Buffers(缓冲) OpenGL ES支持三种缓冲: OpenGL ES •• Color buffer颜色缓冲 •• Depth buffer深度缓冲 •• Stencil buffer模板缓冲 创建缓冲区 OpenGL ES 是一个交互式的渲染系统,假设每帧的开始,你希望初始化所有缓冲区中数据的默认值.调用glClear 函数来清除缓冲区内容,参数mask 指定清除的缓冲区. 你可能不要求清除每一个缓冲区,不在同时清除它们.但如

Git详解之五:分布式Git

为了便于项目中的所有开发者分享代码,我们准备好了一台服务器存放远程 Git 仓库.经过前面几章的学习,我们已经学会了一些基本的本地工作流程中所需用到的命令.接下来,我们要学习下如何利用 Git 来组织和完成分布式工作流程.(伯乐在线注:如果你对Git还不了解,建议从本Git系列第一篇文章开始阅读) 特别是,当作为项目贡献者时,我们该怎么做才能方便维护者采纳更新:或者作为项目维护者时,又该怎样有效管理大量贡献者的提交. 5.1  分布式工作流程 同传统的集中式版本控制系统(CVCS)不同,开发者之

Constant Pool和String Constant Pool详解

Constant Pool常量池的概念: 在讲到String的一些特殊情况时,总会提到String Pool或者Constant Pool,但是我想很多人都不太明白Constant Pool到底是个怎么样的东西,运行的时候存储在哪里,所以在这里先说一下Constant Pool的内容.String Pool是对应于在Constant Pool中存储String常量的区域.习惯称为String Pool,也有人称为String Constant Pool.好像没有正式的命名?? 在java编译好的