oracle内存管理相关知识整理

本文深入探讨Oracle数据库的内存管理机制,包括SGA和PGA的概念、组成、作用,以及如何调整和优化内存设置,确保数据库高效运行。
摘要由CSDN通过智能技术生成

对oracle内存自动管理这一块一直是零零碎碎知识的堆积,有时候突然用起来却又想不起来了。
恰逢最近遇到oracle内存争用方面的案例,决定定下心来把相关知识梳理一下。


oracle在10g时候引入了参数sga_target,实现了对sga的自动调整
在11g的时候,引入了参数memory_target,可以实现自动调整所有内存(自动调整SGA和PGA的大小)

这里,我主要从这几个相关参数入手。

memory_max_target:决定着SGA和PGA总和的最大值


memory_target:缺省值是0,当设置非0值时候,表示对SGA和PGA的自动管理,也是SGA和PGA总和的目标值,该值不能大于memory_max_target的值


sga_target:缺省值是0,当设置非0值时候,表示oracle自动管理sga中的各个内存区(database buffer cache,share pool,large pool,java pool,streams pool)
            是sga自动管理的目标值


sga_max_size:sga大小的最大值


pga_aggregate_target:此参数用来指定所有session总计可以使用最大PGA内存


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

对于oracle11g而言,设置了memory_target参数为非零值时候,便表示开启了sga和pga的自动管理,即使sga_target和pga_aggregate_target都设置为0,
oracle依然可以自动管理sga中各个内存区的调整(buffer cache,shared pool,large pool,java pool,streams pool)


1、当memory_target设置成非0值时候

1.1 sga_target和pga_aggregate_target都已经设置了非0值
  
如果Oracle中已经设置了参数sga_target和pga_aggregate_target,则这两个参数将各自被分配为最小值为他们的目标值。


1.2 sga_target设置大小,pga_aggregate_target没有设置大小

那么pga_aggregate_target初始化值=memory_target-sga_target


1.3 sga_target没有设置大小,pga_aggregate_target设置大小

那么sga_target初始化值=memory_target-pga_aggregate_target


1.4 sga_target和pga_aggregate_target都没有设置大小

 Oracle 11g中对这种sga_target和pag_aggregate_target都没有设定大小的情况下,Oracle将对这两个值没有最小值和默认值。Oracle将根据数据库运行状况进行分配大小。
但在数据库启动时会有一个固定比例来分配:


 sga_target = memory_target*60%


 pga_aggregate_target = memory_target*40%

-----------------------------------------------------------------------------------------
2. 当memory_target设置为0时,(11g的默认值)


11g中默认为0则初始状态下取消了memory_target的作用,完全和10g在内存管理上一致,完全向下兼容。(也有三种情况来对SGA和PGA的大小进行分配)


2.1 sga_target设置值,则自动调节SGA中的shared pool,buffer cache,redo log buffer,java pool,larger pool等内存空间的大小。
   PGA则依赖pga_aggregate_target的大小。sga和pga不能自动增长和自动缩小。


2.2 sga_target和pga_aggregate_target都没有设置


   SGA中的各组件大小都要明确设定,不能自动调整各组件大小。PGA不能自动增长和收缩。


2.3 memory_max_target设置而memory_target = 0这种情况和10g一样

----------------------------------------------------------------------------------
上面都是一些理论方面的阐述,下面我针对几种参数设置情况进行实验,观察sga,pga等值的变化

----查看oracle当前sga和pga的target值


select a.ksppinm name,b.ksppstvl value
    from x$ksppi a,x$ksppcv b
   where a.indx = b.indx
      and (a.ksppinm like '%sga_target%'
  or a.ksppinm like '%pga_aggregate_target%');


1.
---当我将memory_target设置为816m,sga_target=0,pga_aggregate_target=0


SQL> col name format a30
SQL> col value format a30


SQL> select a.ksppinm name,b.ksppstvl value
  2      from x$ksppi a,x$ksppcv b
  3     where a.indx = b.indx
  4        and (a.ksppinm like '%sga_target%'
  5    or a.ksppinm like '%pga_aggregate_target%');


NAME                           VALUE
------------------------------ ------------------------------
sga_target                     0
__sga_target                   511705088     --约等于memory_target的百分之六十
pga_aggregate_target           0
__pga_aggregate_target         343932928     --约等于memory_target的百分之四十


2.当我将memory_target,sga_target,pga_aggregate_target都设置为0时


SQL> alter system set memory_target=0;


系统已更改。


SQL> alter system set sga_target=0;


系统已更改。


SQL> alter system set pga_aggregate_target=0;
alter system set pga_aggregate_target=0
*
第 1 行出现错误:
ORA-02097: 无法修改参数, 因为指定的值无效
ORA-00093: pga_aggregate_target 必须介于 10M 和 4096G-1 之间


这时候在设置pga时候发生报错了,说明当我选择手动管理内存时候,必须给pga设置一个明确的值,也就是说不能存在memory_target和pga_aggregate_target同时为0的情况


现在,我再执行查询sga,pga的语句:


SQL> select a.ksppinm name,b.ksppstvl value
  2      from x$ksppi a,x$ksppcv b
  3     where a.indx = b.indx
  4        and (a.ksppinm like '%sga_target%'
  5    or a.ksppinm like '%pga_aggregate_target%');


NAME                           VALUE
------------------------------ ------------------------------
sga_target                     0
__sga_target                   511705088
pga_aggregate_target           343932928
__pga_aggregate_target         343932928


发现,当memory_target被设置为0,pga_aggregate_target的值自动被设为_pga_aggregate_target 的同等大小。


当sga_target被设置为0时候,且由于memory_target也为0,这时候sga中各个内存区大小需要手动管理。由于我库上共享池之类的内存区设置了最小值,现在将他们全部改为自动


管理,且值为0的情况:
SQL> show parameter memory_target


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
memory_target                        big integer 816M


SQL> show parameter sga_target


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
sga_target                           big integer 512M
SQL>


SQL> show parameter db_cache


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_cache_advice                      string      ON
db_cache_size                        big integer 308M



SQL> show parameter pool


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
_shared_io_pool_size                 big integer 0
buffer_pool_keep                     string
buffer_pool_recycle                  string
global_context_pool_size             string
java_pool_size                       big integer 16M
large_pool_size                      big integer 4M
olap_page_pool_size                  big integer 0
shared_pool_reserved_size            big integer 7969177
shared_pool_size                     big integer 152M
streams_pool_size                    big integer 0
SQL>


下面将db_cache_size,java_pool_size,large_pool_size,shared_pool_sized都设为0


SQL> alter system set db_cache_size=0;


系统已更改。


SQL> alter system set large_pool_size=0;


系统已更改。


SQL> alter system set java_pool_size=0;


系统已更改。


SQL> alter system set shared_pool_size=0;


系统已更改。


--查看修改后的结果
SQL> show parameter db_cache_size;


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_cache_size                        big integer 0


SQL> show parameter pool


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
_shared_io_pool_size                 big integer 0
buffer_pool_keep                     string
buffer_pool_recycle                  string
global_context_pool_size             string
java_pool_size                       big integer 0
large_pool_size                      big integer 0
olap_page_pool_size                  big integer 0
shared_pool_reserved_size            big integer 7969177
shared_pool_size                     big integer 0
streams_pool_size                    big integer 0


这时候,再次将memory_target和sga_target设置为0,看看会发生什么呢??


SQL> alter system set memory_target=0;


系统已更改。


SQL> alter system set sga_target=0;


系统已更改。


成功修改为0值,这时候再看看sga中各个内存区大小的情况:


SQL> show parameter db_cache_size


NAME                                 TYPE        VALUE
------------------------------------ ----------- ----------------------------
db_cache_size                        big integer 332M


SQL> show parameter pool


NAME                                 TYPE        VALUE
------------------------------------ ----------- ----------------------
_shared_io_pool_size                 big integer 0
buffer_pool_keep                     string
buffer_pool_recycle                  string
global_context_pool_size             string
java_pool_size                       big integer 16M
large_pool_size                      big integer 4M
olap_page_pool_size                  big integer 0
shared_pool_reserved_size            big integer 7969177
shared_pool_size                     big integer 152M
streams_pool_size                    big integer 0


当sga改为手动管理后,如果sga各个内存区没有设置明确大小时,oracle自动给各个内存区分配了大小。具体的分配规则我还不太清楚,需要查查,应该也有个比例公式。


----------------------------------------------------------------
顺便提下,oracle分配内存有个最下单位粒度,叫做granule,这个粒度受隐含参数_ksmg_granule_size控制,


来查看下该参数:


SQL> select
  2    x.ksppinm  name,
  3    y.ksppstvl  value,
  4    y.ksppstdf  isdefault,
  5    decode(bitand(y.ksppstvf,7),1,'MODIFIED',4,'SYSTEM_MOD','FALSE')  ismod,
  6    decode(bitand(y.ksppstvf,2),2,'TRUE','FALSE')  isadj
  7  from
  8    x$ksppi x,
  9    x$ksppcv y
 10  where
 11    x.inst_id = userenv('Instance') and
 12    y.inst_id = userenv('Instance') and
 13    x.indx = y.indx and
 14    x.ksppinm like '%_ksmg_granule_size%'
 15  order by
 16    translate(x.ksppinm, ' _', ' ');


NAME                           VALUE                ISDEFAULT ISMOD      ISADJ
------------------------------ -------------------- --------- ---------- -----
_ksmg_granule_size             4194304              TRUE      FALSE      FALSE


也就是说我现在库上granule的粒度值为4M,即oracle在分配内存的时候是以4M为单位的,也就意味着比如sga的大小都是4的倍数。


下面我做个实验来验证一下:


SQL> show parameter sga_target


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
sga_target                           big integer 512M
SQL>
SQL>
SQL> alter system set sga_target=1m;    ---------设置sga_target值为1m,然后查看结果,发现sga_target为4M


系统已更改。


SQL> show parameter sga_target


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
sga_target                           big integer 4M


SQL> alter system set sga_target=6m;    ---------接着将sga_target值设置为6m,发现结果是8m,也验证了我之前所说的,oracle分配内存时候是以granule粒度为单位的。


系统已更改。


SQL> show parameter sga_target


NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
sga_target                           big integer 8M


------------------------------------------------------------------------------------------------
稍微总结一下:对于11g而言当设置memory_target参数为非0值的时候,说明oracle自动管理sga和pga,包括sga中各个内存区的自动管理,即使sga_target设置为0
          当memory_target设置为0时候,这时候oracle内存管理方式就和10g一样了,通过设置sga_target来确定sga是自动管理还是手动管理。并且当memory_target时候,需要给pga_aggregate_target设置一个非零值。


关于选择内存自动管理还是手动管理,说法各有千秋,就我个人而言,遇到的大多数重要生产库,都是采用手动管理的方式,明确了各个内存区的大小。
而且自动管理还容易出现一些bug,以及内存方面的争用,比如shared pool和buffer cache。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值