从Oracle 10g开始,Oracle提供了自动SGA的管理(简称ASMM,即Automatic Shared Memory Management)新特性。所谓ASMM,就是指我们不再需要手工设置 shared pool、buffer pool等若干内存池的大小,而是为SGA设置一个总的大小尺寸即可。Oracle 10g数据库会根据系统负载的变化,自动调整各个组件的大 小,从而使得内存始终能够流向最需要它的地方。
比如,假设某个系统,白天属于OLTP应用,因此会需要较多的buffer cache。而该系统在晚上属于DSS应用。对于DSS应用,很多的SQL语句由于都是进行全表 扫描,因此都会采取并行方式完成。我们知道,并行时需要靠若干的从属进程完成工作,而从属进程会从large pool中进行分配。于是,晚上会需要较多的 large pool。如果我们启用了ASMM,则数据库会根据负载的变化而自动的对内存大小进行调整,就不需要DBA进行手工调整了。
Oracle 10g提供了一个新的初始化参数:sga_target来启动ASMM,该参数定义了整个SGA的总容量。同时,初始化参数statistics_level必须设置为typical 或all才能启动ASMM,否则如果设置为basic,则关闭ASMM。
ASMM只能自动调整5个内存池的大小,它们是:shared pool、buffer cache、large pool、java pool和stream pool。我们不再需要设置shared_pool_size 、db_cache_size、large_pool_size、java_pool_size、streams_pool_size这五个初始化参数。而其他的内存池,比如log buffer、keep buffer cache等 仍然需要DBA手工进行调整。
举例来说,假设我们将sga_target设置为500MB,表示SGA总容量为500MB。但是如果我们需要配置100MB的keep buffer cache,则必须手工设置参数 db_keep_cache_size为100MB。同时如果设置参数log_buffer为3MB,那么shared pool、buffer cache等可以调整的5个部分的总容量就是397MB(500-100- 3=397)。
Oracle 10g还提供了另一个初始化参数sga_max_size。sga_target的值不能超过sga_max_size的值,修改sga_max_size时,必须重启实例才能生效,而 sga_target则可以在线修改,立即生效,无须重启实例。
为了实现ASMM,Oracle新引入了一个名为MMAN(Memory Manager)的后台进程。每隔很短的一段时间,MMAN进程就会启动,然后去询问一下Oracle提供的各 个内存组件顾问,比如有buffer cache顾问,也有shared pool顾问,由这些顾问根据当前的负载情况,将这5个可以自动调整的内存池的、建议的大小尺寸 ,返回给MMAN。于是,MMAN进程就会根据该返回的值,来设置各个内存池。同时,如果我们使用了spfile,还会将这些顾问得出的建议值写入spfile里。这 样,下次启动实例时,就可以直接把顾问得出的建议值拿来作为启动内存池的依据了。
如果我们启用了ASMM,同时又手工设置了可以自动调整大小的内存池的尺寸,比如设置了参数shared_pool_size为一个非0值的时候,会怎么样?对于Oracle 10g来说,我们为自动调整大小的内存组件设置了值,则会以我们设置的值作为自动调整的最小值。也就是说,假设sga_target为4GB,而我们将 shared_pool_size设置为600MB,则MMAN在进行自动调整时,永远不会将shared pool设置为600MB以下。
实际上,为了使用ASMM,Oracle为这5个可自动调整的组件又提供了5个控制它们大小尺寸的参数,以“__”(两个下画线开头)。我们把当前的spfile导出 到pfile里。
SQL> create pfile='/u01/init.ora' from spfile;
SQL> !vi /u01/init.ora
打开该pfile以后,我们会发现文件的前5行,会显示如下的内容(具体值可能不一样):
ora10g.__db_cache_size=134217728
ora10g.__java_pool_size=4194304
ora10g.__large_pool_size=4194304
ora10g.__shared_pool_size=62914560
ora10g.__streams_pool_size=0
可以看到,这5个初始化参数都以“__”开头,后面的部分与我们手工设置内存池大小的参数相同。比如__db_cache_size与db_cache_size对应等。这种以“ _”开头的参数我们叫做隐藏参数。所谓隐藏参数,就是没有官方文档对其含义进行说明的参数。这种参数会根据版本的不同而发生改变。这5个隐藏参数( 比如__shared_pool_size)由MMAN进程负责修改,而与之相对应的其他参数(比如shared_pool_size)则由DBA进行设定。因此,当我们启动数据库时,数据 库内核会在初始化参数__shared_pool_size与shared_pool_size之间进行比较。如果shared_pool_size没有设定,或设定为0,或设定的值比 __shared_pool_size小,则以MMAN自动调整的值来设置内存池的尺寸。否则,以DBA设定的值来设置内存池的尺寸。
如果我们在数据库运行过程中,修改了某个可自动调整的内存池的大小,这时会怎么样?如果我们设置的值比MMAN自动调整出来的值要大,则该内存池立即 调整为设定的值的大小,同时我们所设定的值作为MMAN新的、自动调整的最小值;反之,如果设置的值比MMAN自动调整出来的值要小,则该内存池的大小不 会变化,而我们所设置的值则只作为自动调整的最小值存在。比如,当前MMAN自动调整出来的shared pool大小为150MB,也就是__shared_pool_size为150MB ,同时shared_pool_size为60MB。这时,如果我们将参数shared_pool_size从60MB设置为100MB的话,则shared pool的大小仍然为150MB,但是新设置的 100MB将作为自动调整时的下限;如果我们将参数shared_pool_size从60MB设置为200MB,则shared pool立即扩张,从150MB扩张到200MB,同时200MB也将作 为自动调整的新的下限。
我们来验证一下。视图v$sga_dynamic_components里记录了能够动态调整的各个内存池的大小。
SQL> SELECT component, current_size/1024/1024 size_mb
2 FROM v$sga_dynamic_components where component='shared pool';
COMPONENT SIZE_MB
------------------------------------ ------------
shared pool 80
当前MMAN自动调整出来的shared pool大小为80MB。
SQL> alter system set shared_pool_size=70M;
SQL> SELECT component, current_size/1024/1024 size_mb
2 FROM v$sga_dynamic_components where component='shared pool';
COMPONENT SIZE_MB
------------------------------------ ------------
shared pool 80
我们将shared_pool_size设定为70MB,小于自动调整出来的值。可以看到,shared pool没有缩小,仍然是80MB。我们再将其从80MB扩大到100MB。
SQL> alter system set shared_pool_size=100M;
SQL> SELECT component, current_size/1024/1024 size_mb
2 FROM v$sga_dynamic_components where component='
shared pool';
COMPONENT SIZE_MB
------------------------------------ ------------
shared pool 100
显然,只要我们设定的值比自动调整出来的值大,就会立即生效。
同时,如果当前我们启用了ASMM,同时并没有为这5个可以自动调整的内存池参数指定具体的值。当数据库在ASMM状态下运行一段时间以后,我们再禁用ASMM ,会发生什么?我们来看下面的试验。
SQL> select name,value from v$parameter
2 where name in('shared_pool_size','db_cache_size','
java_pool_size','large_pool_size',' streams_pool_size');
NAME VALUE
-------------------- --------------
shared_pool_size 96468992
large_pool_size 0
java_pool_size 0
streams_pool_size 0
db_cache_size 0
可以看到,除了shared pool为DBA指定以外(因为shared_pool_size大于0),其他的内存池都由ASMM指定。
SQL> select component, current_size FROM v$sga_dynamic_
components 2 where component like '%pool' or component=
'DEFAULT buffer cache';
COMPONENT SIZE_MB
---------------------------------- -----------
shared pool 138412032
large pool 4194304
java pool 4194304
streams pool 0
DEFAULT buffer cache 373293056
我们看到,ASMM根据当前的负载情况,为这5个内存池指定了大小。
SQL> alter system set sga_target=0;
SQL> select name,value from v$parameter
2 where name in('shared_pool_size','db_cache_size','
java_pool_size','large_pool_size',' streams_pool_size');
NAME VALUE
-------------------- --------------
shared_pool_size 138412032
large_pool_size 4194304
java_pool_size 4194304
streams_pool_size 0
db_cache_size 373293056
当我们将sga_target设置为0,从而禁用ASMM时,会发现,Oracle会自动将当前内存池的大小赋给对应的初始化参数(shared_pool_size、db_cache_size等 )。同时我们也可以注意到,shared_pool_size的值也不再是DBA当时指定的96468992,而是被ASMM自动调整出来的138412032所覆盖。
源文档 <http://book.51cto.com/art/200806/75642.htm>
PGA管理
作为一个复杂的Oracle数据库系统来说,每时每刻都要处理不同用户所提交的SQL语句,获取数据并返回数据给用户。前面已经说到,解析SQL语句的工作是 在Oracle实例中的shared pool所完成的。那么对于每个session来说,其执行SQL语句时所传入的绑定变量放在哪里?而且,对于那些需要执行比较复杂SQL 的session来说,比如需要进行排序(sort)或hash连接(hash-join)时,这时,这些session所需要的内存空间又从哪里来?另外,还有与每个session相 关的一些管理控制信息又放在哪里?对于诸如此类与每个session相关的一些内存的分配问题,Oracle通过引入PGA这个内存组件来进行解决。
5.7.1 PGA的概念及其包含的内存结构
PGA按照Oracle官方文档解释,叫做程序全局区(Program Global Area),但也有些资料上说还可以理解为进程全局区(Process Global Area)。这两者没 有本质的区别,它首先是一个内存区域,其次,该区域中包含了与某个特定服务器进程相关的数据和控制信息。每个进程都具有自己私有的PGA区,这也就意 味着,这块区域只能被其所属的进程进入,而不能被其他进程访问,所以在PGA中不需要latch这样的内存结构来保护其中的信息。
笼统地说,PGA里包含了当前进程所使用的有关操作系统资源的信息(比如打开的文件句柄等)以及一些与当前进程相关的一些私有的状态信息。每个PGA区 都包含以下两部分。
固定PGA部分(Fixed PGA):这部分包含一些小的固定尺寸的变量,以及指向变化PGA部分的指针。
变化PGA部分(Variable PGA):这部分是按照堆(Heap)来进行组织的,所以这部分也叫做PGA堆。PGA堆中所包含的内存结构包括:
有关一些固定表的永久性内存。
如果session使用的是专用连接方式(dedicated server),则还含有用户全局区(User Global Area,UGA)子堆。如果session使用的是共享连接方式 (shared server),则UGA位于SGA中。UGA是PGA中的最重要的部分。
调用全局区(Call Global Area,CGA)子堆。
UGA是包含与某个特定session相关信息的内存区域,比如session的登录信息以及session私有的SQL区域等。每个UGA也包含以下两个部分。
固定UGA部分(Fixed UGA):这部分包含一些小的固定尺寸的变量,以及指向变化UGA部分的指针。
变化UGA部分(Variable UGA):这部分也是按照堆来进行组织的,可以从X$KSMUP视图中看到有关UGA堆的分布情况。UGA堆的分布与open_cursors、 open_links等参数有关系。所谓的游标(cursor)就是放在这里的,游标指向shared pool里的包含SQL文本以及执行计划等的对象。UGA堆中所包含的内存结 构介绍如下。
私有SQL区域(Private SQL Area):这部分区域包含绑定变量信息以及运行时的内存结构等数据。每一个发出SQL语句的session都有自己的私有SQL区域。 这部分区域又可分成以下两部分。
永久内存区域:这里存放了相同SQL语句多次执行时都需要的一些游标信息,比如绑定变量信息、数据类型转换信息等。这部分内存只有在游标被关闭时才会 被释放。
运行时区域:在处理SQL语句时的第一步就是要创建运行时区域,这里存放了当SQL语句运行时所使用的一些信息。对于DML(INSERT、UPDATE、DELETE)语句 来说,SQL语句执行完毕就释放该区域;而对于查询语句(SELECT)来说,则是在所有数据行都被获取并传递给用户以后被释放,或者该查询被取消以后也会 被释放。
Session相关的信息。这部分信息包括以下几部分。
正在使用的包(package)的状态信息。
使用alter session这样的命令所启用的跟踪信息,或者所修改的session级别的优化器参数(optimizer_mode)、排序参数(sort_area_size等)、修改的 NLS参数等。
所打开的db links。
可使用的角色(roles)等。
工作区(Work area):这块区域主要用来存放执行SQL的过程中所产生的中间数据,比如排序时,需要在这里存放排序过程中的中间数据。这部分占据了PGA 中的大部分空间。其大小依赖于所要处理的SQL语句的复杂程度而定。如果SQL语句包含诸如group by、hash-join等这样的操作,则会需要很大的SQL工作区 域。实际上,我们调整PGA也就是调整这块区域。
而UGA所处的位置完全由session连接的方式决定:
如果session是通过共享服务器(shared server)方式登录到数据库的,则毫无疑问,UGA必须能够被所有进程访问,所以在这种情况下,UGA是从SGA中进行 分配的。进一步说,如果SGA中设置了large pool,则UGA从large pool里进行分配;否则,如果没有设置large pool,则UGA只能从shared pool里进行分配 。
如果session是通过专用服务器(dedicated server)方式登录到数据库的,则UGA是从进程的PGA中进行分配的。
源文档 <http://book.51cto.com/art/200806/75643.htm>
PGA自动管理
在Oracle 9i之前,我们主要是通过设置sort_area_size、hash_area_size等参数值(通常都叫做*_area_size)来管理PGA的使用,不过严格说来,是对PGA 中的UGA进行管理。但是,这里有个问题,就是这些参数都是针对某个session而言的,也就是说设置的参数值对所有登录到数据库的session都生效。在数据 库实际运行过程中,总有些session需要的PGA多,而有些session需要的PGA少。如果都设置一个很小的*_area_size,则会使得某些SQL语句运行时由于需要 将临时数据交换到磁盘而导致效率低下。而如果都设置一个很大的值,又有可能一方面浪费空间;另一方面,消耗过多内存可能导致操作系统其他组件所需 要的内存短缺,而引起数据库整体性能下降。所以如何设置*_area_size的值一直都是DBA很头疼的一个问题。
而从Oracle 9i起(当然也包括Oracle 10g)所引入的一个新的特性可以有效的解决这个问题,这个特性就是自动PGA管理。
首先,设置workarea_size_policy参数。该参数为auto(也是默认值)时,表示启用PGA自动管理;而设置该参数为manual时,则表示禁用PGA自动管理,仍 然沿用Oracle 9i之前的方式,也就是使用*_area_size对PGA进行管理。
然后,DBA可以根据数据库的负载情况估计所有session大概需要消耗的PGA的内存总和,然后把该值设置为初始化参数pga_aggregate_target的值即可。 Oracle会按照每个session的需要为其分配PGA,同时会尽量维持整个PGA的内存总和不超过该参数所定义的值。这样的话,Oracle就能尽量避免整个PGA的内 存容量异常增长而影响整个数据库的性能。从而,就有效的解决了设置*_area_size所带来的问题。
不过遗憾的是,Oracle 9i下的PGA自动管理只对专用连接方式有效,对共享连接方式无效。Oracle 10g以后对两种连接方式都有效。
在PGA中,对性能影响最大的就是SQL工作区了。通常来说,SQL工作区越大则对于SQL语句的执行的效率就高,从而对于用户的响应时间就越少。理想情况下 ,SQL工作区应该可以容纳SQL执行过程中所涉及的所有输入数据和控制信息。当然,这只是理想情况,现实往往总是不能尽如人意,很多情况下SQL工作区是 不能容纳执行SQL所需要的内存空间的,从而不得不交换到临时表空间里。为了衡量执行SQL所需要的内存与实际分配给该SQL的SQL工作区之间的契合程度, Oracle将所分配的SQL工作区大小分成以下三种类型。
optimal尺寸:SQL语句能够完全在所分配的SQL工作区内完成所有的操作。这时的性能最佳。
onepass尺寸:SQL语句需要与磁盘上的临时表空间交互一次才能够在所分配的SQL工作区中完成所有的操作。
multipass尺寸:由于SQL工作区过小,从而导致SQL语句需要与磁盘上的临时表空间交互多次才能完成所有的操作。这个时候的性能将急剧下降。
当系统整体负载不大时,Oracle倾向于为每个session的PGA分配optimal尺寸大小的SQL工作区。
而随着负载上升,比如连接的session逐渐增多导致同时执行的SQL语句越来越多时,Oracle就会倾向于为每个session的PGA分配onepass尺寸大小的SQL工作 区,甚至是multipass尺寸的SQL工作区了。
我们一旦设置了pga_aggregate_target以后,所有的*_area_size就将被忽略。那么,我们该如何来设置该参数的值呢?这依赖于数据库的用途,如果数据库 为OLTP(联机事务处理)应用的,则其应用一般都是小的短的进程,所需要的PGA也相应较少,所以该值该值通常为总共分配给Oracle实例的20%,另外的80% 则给了SGA;如果数据库为OLAP(DSS)(数据仓库或决策分析)应用的,则其应用一般都是很大的,运行时间很长的进程,因此需要的PGA就多。所以通常为 PGA分配50%的内存。而如果数据库为混合类型的,则情况比较复杂,一般会先分配40%的初始值,而后随着数据库的应用,而不断对PGA进行监控,并进行相 应的调整。
比如,对于8GB物理内存的数据库服务器来说,按照Oracle推荐的,分配给Oracle实例的内存为物理内存的80%。那么对于OLTP应用来说, pga_aggregate_target的值大约就是1310MB((8192MB×80%)×20%)。而对于OLAP来说,则该值大约就是3276MB((8192MB×80%)×50%)。
当然,这里所说的都是对于一个新的数据库来说,初始设置的值。这些值并不一定正确,可能设置过大,也可能设置过小。必须随着系统的不断运行,DBA需 要不断监控,从而对其进行调整。
Oracle为了帮助我们确定这个参数的值,引入了一个新的视图v$pga_target_advice。为了使用该视图,需要将初始化参数statistics_level设置为typical (默认值)或all。
SQL> select
2 round(pga_target_for_estimate /(1024*1024)) "Target (M)",
3 estd_pga_cache_hit_percentage "Est. Cache Hit %",
4 round(estd_extra_bytes_rw/(1024*1024)) "Est. ReadWrite (M)",
5 estd_overalloc_count "Est. Over-Alloc"
6 from v$pga_target_advice
7 /
Target (M) Est. Cache Hit % Est. ReadWrite (M) Est. Over-Alloc
------------------------------------------------------------------------
15 34 264 1
30 34 264 0
45 34 264 0
60 67 66 0
72 67 66 0
84 67 66 0
96 67 66 0
108 67 66 0
120 67 66 0
……
360 67 66 0
480 67 66 0
该输出告诉我们,按照系统目前的运转情况,我们PGA设置的不同值所带来的不同效果。根据该输出,随着我们增加PGA的尺寸, estd_pga_cache_hit_percentage不断增加,同时estd_extra_bytes_rw(表示onepass、multipass读写的字节数)不断减小。从上面的结果我们可以知道, 将pga_aggregate_target设置为60MB是最合理的,因为即便将其设置为480MB,命中率也不会有所提高。
转载于:https://blog.51cto.com/19880614/1184071