解决0RA-04031故障

1.客户反应报表数据很慢,简单查询5分钟都出不来。

2.登陆数据库服务器检查日志:
Thu Mar 21 16:20:30 2013
Errors in file /opt/oracle/diag/rdbms/rptdw/rptdw2/trace/rptdw2_lms0_9538.trc (incident=144231):
ORA-04031: unable to allocate 4064 bytes of shared memory ("shared pool","unknown object","sga heap(1,0)","gcs dynamic r")
Incident details in: /opt/oracle/diag/rdbms/rptdw/rptdw2/incident/incdir_144231/rptdw2_lms0_9538_i144231.trc

3.了解一下shared pool的原理
library cache包含 SQL语句,分析的代码,执行计划等
data dictionary cache包含 table, column等对象的定义以及权限的信息

主要包含如下组件:
Permanent Area
Segmented Arrays(锁、事务、资源等)
Library Cache
Row Cache
Reserved Area

查看共享池大小和共享池保留区大小
select * from v$sga_dynamic_components ;
shared pool 3019898880

SQL> show parameter shared
NAME TYPE
------------------------------------ --------------------------------
VALUE
------------------------------
shared_pool_reserved_size big integer
154350387

查看共享池隐含参数
SELECT ksppinm, ksppstvl, ksppdesc
FROM x$ksppi x, x$ksppcv y
WHERE x.indx = y.indx AND TRANSLATE (ksppinm, '_', '#') LIKE '#share%';
ksppinm ksppstvl ksppdesc
_shared_pool_reserved_pct 5 percentage memory of the shared pool allocated for the reserved area
_shared_pool_reserved_min_alloc 4400 minimum allocation size in bytes for reserved area of shared pool
_shared_pool_max_size 0 shared pool maximum size when auto SGA enabled
_shared_pool_minsize_on FALSE shared pool minimum size when auto SGA enabled
_shared_io_pool_size 0 Size of shared IO pool
_shared_iop_max_size 536870912 maximum shared io pool size
_shared_io_pool_buf_size 1048576 Shared IO pool buffer size
_shared_io_pool_debug_trc 0 trace kcbi debug info to tracefile
_shared_io_set_value FALSE shared io pool size set internal value - overwrite zero user size
_shared_server_load_balance 0 shared server load balance
_shared_server_num_queues 2 number of shared server common queues


转储shared pool 共享内存的内容
SQL> alter session set events 'immediate trace name heapdump level 2' ;

Session altered.

直观查看shared pool结构:
FREE LISTS:
Bucket 0 size=32
Bucket 1 size=40
Bucket 2 size=48
Bucket 3 size=56
Bucket 4 size=64
Chunk 09e3fffc0 sz= 64 free " "
Bucket 5 size=72
Bucket 6 size=80
Chunk 09d3fffb0 sz= 80 free " "

RESERVED FREE LISTS:
Reserved bucket 0 size=32
Reserved bucket 1 size=4400
Reserved bucket 2 size=8216
Reserved bucket 3 size=8696
Reserved bucket 4 size=8704
Reserved bucket 5 size=8712
Reserved bucket 6 size=8720
Reserved bucket 7 size=9368
Reserved bucket 8 size=9376
Reserved bucket 9 size=12352
Reserved bucket 10 size=12360
Reserved bucket 11 size=16408
Reserved bucket 12 size=32792
Reserved bucket 13 size=65560
Chunk 099c00088 sz= 212808 R-free " "
Chunk 09a000088 sz= 212808 R-free " "
Chunk 09a400088 sz= 212808 R-free " "
Chunk 09a800088 sz= 212808 R-free " "


SQL> show parameter user_

NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
license_max_users integer 0
user_dump_dest string /opt/oracle/diag/rdbms/etldb2/
etldb2/trace

了解 X$KSMSP视图(Kernal Storage Memoty Management SGA HeaP)

1、其中每一行都代表shared pool中的一个chunk(内存块)
2、主要字段的解释
ksmchcom:是注释字段,每个内存块被分配以后,注释会添加在该字段中。
ksmchsiz:代表块大小
ksmchcls:代表类型,主要有4类
1)free
free chunks 不包含任何对象的chunk,可以不受限制的被自由分配。
2)recreate
recreatable chunks:包含可以被临时移出内存的对象,在需要的时候,这个对象可以被重新创建。例如,许多存储共享sql代码的内存都是可以重建的。
3)freeable
freeable chunks:包含session周期或调用的对象,随后可以释放。这部分内存有时候可以全部或部分提前释放,但是注意,由于某些对象是中间过程产生的,这些对象不能临时被移除内存(因为不可以重建)
4)perm
permanent memory chunks:包含永久对象,通常不能独立释放。

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

解决思路:
使用flush shared pool 缓解共享池问题
1、 刷新共享池:
alter system flush shared pool;刷新共享池可以帮助合并碎片,强制老化sql,释放共享池,但是这通常是不推荐的做法。因为
1)flush shared pool 会导致当前未使用的cursor被清除共享池,如果这些sql随后需要执行,那么数据库将经历大量的硬解析,系统将会经历严重的cpu争用,数据库将会产生激烈的latch竞争。
2)如果应用没有使用绑定变量,大量类似的sql不停的执行,那么flush shared pool可能会带来短暂的改善,数据库很快会回到原来的状态。
3)如果shared pool很大,并且系统非常的繁忙,刷新shared pool可能会导致系统挂起,对于类似系统尽量在系统空闲时进行。

shared_pool_reserved_size参数的设置和作用
1、shared_pool_reserved_size参数指定了保留的共享池空间,用于满足大的连续的共享池空间请求。当共享池出现多碎片时,请求大块空间会导致oracle大范围地查找并释放共享池内存来满足请求,由此可能会带来较为严重的性能下降,设置合适的shared_pool_reserved_size参数和_shared_pool_reserved_min_alloc参数可以避免由此导致的性能下降。_shared_pool_reserved_min_alloc这个参数控制这保留内存的控制和分配。缺省值为4400bytes,即当请求的内存大于这个值时就进入共享池保留空间分配内存。
2、查看v$shared_pool_reserved视图可以判断共享池问题的引发原因。
select free_space,avg_free_size,used_space,avg_used_size,request_failures,last_failure_size from v$shared_pool_reserved;
若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,那么是因为在库高速缓冲缺少连续空间导致ORA-04031错误。对于这一类情况应该考虑降低_shared_pool_reserved_min_alloc,以放入更多的对象到共享池保留空间并加大shared_pool_size。

表面看是共享池资源不足语句造成的。
查询一下共享池参数配置
SELECT free_space, avg_free_size,used_space, avg_used_size, request_failures,last_failure_size FROM v$shared_pool_reserved;
FREE_SPACE AVG_FREE_SIZE USED_SPACE AVG_USED_SIZE REQUEST_FAILURES LAST_FAILURE_SIZE
129027376 781984.097 100931920 611708.6061 1209 4000


SQL> SELECT nam.ksppinm NAME, v.ksppstvl VALUE
FROM x$ksppi n, x$ksppsv v
WHERE n.indx = v.indx AND n.ksppinm LIKE '%shared%'
ORDER BY 1;
_shared_pool_reserved_min_alloc
4400

通过REQUEST_FAILURES > 0 并且 LAST_FAILURE_SIZE < SHARED_POOL_RESERVED_MIN_ALLOC ,可以知道是因为共享池库缓存不足造成,可以降低_shared_pool_reserved_min_alloc
并且增加share_pool_size。


5.我的处理方法
因为我们使用了数据库内存自动管理,不方便修改share pool的大小,并且修改隐藏参数是有风险的,可能会引发其它的bug,我觉得可以从sql语句上控制产生ORA-04031发生。
通过sql语句监控可以知道发生错误时候我们执行了清理历史分区的语句,类似下面的:
alter table DW.TW_RS_I2000_PLATFORM_H drop partition P2012101415 ;
alter table DW.TW_RS_I2000_PLATFORM_H drop partition P2012102223 ;
alter table DW.TW_RS_I2000_PLATFORM_H drop partition P2012103107 ;
alter table DW.TW_RS_I2000_STORAGE_H drop partition P2012100815 ;

清除这些分区之前,oracle都需要把这些块读入共享池,然后再处理,既然share pool不足以一次装这么多新的数据块,那我们可以让共享池分批处理这些数据,就可以有效的避免ORA-04031错误

通过一个简单的python脚本,把删除语句加工一下,每200行插入清理共享池的语句即可
#!/usr/bin/python
#Filename : droptbs.py
import os
num = 0
file_src = open('/home/etl/etl_script/lisx/dropdw.txt')
file_dest = open('/home/etl/etl_script/lisx/dropdw2.txt','a')
for l in file_src.xreadlines():
num += 1
file_dest.write(l)
if num % 200 == 0:
file_dest.write('alter system flush shared_pool ; ')
file_src.close()
file_dest.close()
再次执行删除清理表空间的脚本,数据库响应正常。

原文地址:https://www.cnblogs.com/caibird2005/p/3607241.html