前言

生产环境日志中,频繁报错

ORA-04031: unable to allocate 138032 bytes of shared memory ("shared pool","SELECT /*+ OPT_PARAM('_fix_c...","SQLA^e4a8c383","qks3tstr :qks3tStrAPS")。

ORA-04031: 无法分配 16968 字节的共享内存 ("shared pool", "DRIXMD", "PLMCD^d6af968b","BAMIMA: Bam Buffer")

同时很多正常的sql都无法执行。应用重启之后还是会出现。

还有这个错误也是类似:ORA-01000: 超出打开游标的最大数

原因与解决方案

1. 没有绑定变量造成shared_pool碎片过多

(1)这种情况比较常见。使用sql操作数据库时要多用占位符,变量。

(2)如果使用Mybatis访问数据库时,mapper文件中要多用:#变量名,少用:$变量名。

2. shared_pool_size,Large_pool,Java_pool设置太小

(1)shared_pool_size如果设置的太小可以简单加大shared_pool,临时的解决方法就是alter system flush shared_pool。也可以通过设置sga_target,memory_target这些总体参数来连带设置shared_pool的大小。通过错误信息的提示很容易判断(Ora-04031 cannot allocate .. memeory in [large_pool])

(2)解决方法就是简单的加大 Large_pool or Java_pool

3. 过度的开CURSOR而不关闭。

目前,此问题发生的越来越多,在各种语言中都会发生。加大Shared_pool或者flush shared_pool往往只能延迟问题出现的时间,而无法根除此问题。日志中会出现如下错误,ORA-01000: 超出打开游标的最大数。

判断办法

假如出来的值特大(以万为单位)时,基本就可以确定是这个原因了。

解决方法就是检查程序,看看是否存在没有正常关闭cursor的情况。

对于JAVA来说,就是开启之后没有关闭Statement,一般使用jdbc时会出现。如果使用mybatis或者hibernate不太容易出现。

还有就是可以排查下存储过程,视图是否存在类似情况。

通过数据库可以查询是哪句SQL哪台服务器占用的游标数比较多。然后做针对性优化。

一般来说,每分配 1 MB 内存可给每个连接用户分配 50 个游标。

-- 当前已经开启的游标总数量
select count(*) from v$open_cursor

-- 查询游标相关参数,open_cursors是一个会话一次最多可以拥有的游标数
show parameter cursors;

--查询游标数大于100的session
select sid,count(*) from v$open_cursor group by sid having count(*) > 100
select * from v$open_cursor where sid = 3418

--查询sql内容
select * from V$SQL t where t.sql_id in ('bvkckyya5hyqx');

-- 数据库会话信息查询(服务器主机名)
SELECT * FROM v$session WHERE sid in (3418)