22、library cache_2(keep包、library cache的lock和pin、清空sql/执行计划、flush shared_pool)
有两个包:
1、DBMS_SHARED_POOL.KEEP,DBMS_SHARED_POOL包里有一个存储过程KEEP
2、DBMS_SHARED_POOL.PURGE,有一个存储过程PURGE
这两个包什么含义,怎么用?
1、DBMS_SHARED_POOL.KEEP:什么时候用KEEP呢?
oracle有一个问题,就是要执行包里面的某一个存储过程或者函数的时候,会把整个包调到library cache里面去,这时候,free里面的chunk很小(小碎片),这时候就会报ORA-04031错误,它会提示在加载哪个包的时候出现问题,如果经常出现这个问题,我们就有必要把这个package提前把它keep进library里去,让它缓存在library cache里,防止出问题;
碰到ORA-04031错误的时候,还有另外一个解决方案:shared pool里面专门有一个保留区;第一,把这个保留区做大一些; 第二,把进入保留区的这个size(门槛)降低一些
2、DBMS_SHARED_POOL.PURGE:
有时候,我们希望清空一下SQL以及执行计划,因为这个SQL比较差,希望系统重新解析一下,这时候就使用DBMS_SHARED_POOL.PURGE这个包
ORA-04031错误怎么出现的(经验值):
1、硬解析多:小、碎的free chunk
2、突然来了一个需要比较大的空间的package或者sql:需要空间大,还需要全部加载
查询包或者SQL是否被keep:
select * from v$db_object_cache
查看在library cache里面缓存着什么:
select distinct namespace from v$db_object_cache; -- 这个SQL不要在生产里面跑,很危险
KEEP一个包:
查询包:
select * from v$db_object_cache where namespace='BODY';
首先执行一个脚本,把DBMS_SHARED_POOL.KEEP生成一下:
SQL> @?/rdbms/admin/dbmspool.sql
Package created.
Grant succeeded.
KEEP包:
SQL> exec dbms_shared_pool.keep('DBMS_SYSTEM','P')
PL/SQL procedure successfully completed.
再次查询:
select * from v$db_object_cache where namespace='BODY';
KEEP一个SQL:
查询SQL:
select * from v$sqlarea;
KEEP SQL:
SQL> exec dbms_shared_pool.keep('0000000064CB4510,2269249538','C') --这个大写的C可以随便写,只要不是P、T、R、Q就行
-- 0000000064CB4510:ADDRESS
-- 2269249538: HASH_VALUE
清空一下SQL以及执行计划
有时候,我们希望清空一下SQL以及执行计划,因为这个SQL比较差,希望系统重新解析一下
1、清空一个SQL以及他的执行计划:希望一个SQL重新解析一下
2、还有就是,一个packge占用的空间很大,但是执行次数很少,也清一下
如何清空一个SQL呢?
begin
DBMS_SHARED_POOL.PURGE('000000008A8AD1A8,1372979452','C');
end;
-- 000000008A8AD1A8:SQL对应的address
-- 1372979452: SQL对应的hash值
清空整个shared pool:
SQL> alter system flush shared_pool;
System altered.
建议:一个一个去清,不要一次性清空
oracle的MOS网站:
https://support.oracle.com
library cache里面的lock和pin
模拟library cache的lock和pin:
1、建立一个存储过程(session 1里):
SQL> create or replace procedure p0001 as
begin
dbms_lock.sleep(1000);
end;
/
Procedure created.
然后执行这个存储过程:
SQL> exec p0001; -- 一直正在执行着
查询会话:
select * from v$session where username='SYS' and status='ACTIVE';
查询正在执行的SQL:
select * from v$sql where sql_id='2kf3164ugb2vz';
查询锁:
select event,v.SECONDS_IN_WAIT,v.WAIT_TIME from v$session v where username='SYS' and status='ACTIVE'and sid=20;
这里是手工加了一个锁
2、然后在session 2里,去编译session 1正在执行的(也就是加一个X锁):
SQL> alter procedure p0001 compile;
查询锁(session 2加不上X锁):
select event,v.SECONDS_IN_WAIT,v.WAIT_TIME from v$session v where username='SYS' and status='ACTIVE'and sid!=20;
3、在session 3里再执行一次:
SQL> exec p0001;
查询锁(加不上lock):
select event,v.SECONDS_IN_WAIT,v.WAIT_TIME from v$session v where username='SYS' and status='ACTIVE'and sid!=20;
4、在session 4里再执行一次:
SQL> exec p0001;
查询锁(加不上lock):
select event,v.SECONDS_IN_WAIT,v.WAIT_TIME from v$session v where username='SYS' and status='ACTIVE'and sid!=20;
只有第一个是pin,之后的都是lock锁
注意:lock和pin,lock是解决依赖关系的;pin是执行的瞬间pin住,解决对某一个对象执行的瞬间并发
在生产里面,特别的害怕:
1、ddl(DDL会导致表、视图里所依赖的一连串的存储过程要重新编译);
2、procedure
查询依赖关系:
select * from dba_dependencies
查询包的依赖关系:
select * from dba_dependencies s where s.referenced_type='VIEW' and type='PACKAGE';