Oracle的内存配置与oracle性能息息相关。关于内存的配置,是最影响Oracle性能的配置。内存还直接影响到其他两个重要资源的消耗:CPU和IO.
程序代码(PLSQL、Java);
关于已经连接的会话的信息,包括当前所有活动和非活动会话;
程序运行时必须的相关信息,例如查询计划;
Oracle进程之间共享的信息和相互交流的信息,例如锁;
那些被永久存储在外围存储介质上,被cache在内存中的数据(如redo log条目,数据块)。
每个Oracle数据库都是由Oracle Instance(实例)与数据库(数据文件,控制文件、重做日志文件)组成,其中所谓实例就是用户同数据库交互的媒介,用户通过于一个实例相连来操作数据库。而实例又是由统一的内存结构(SGA,PGA,UGA)和一批内存驻留进程组成。实例在操作系统中用ORACLE_SID来标识,在Oracle中用参数INSTANCE_NAME来标识, 它们两个的值是相同的。数据库启动时,系统首先在服务器内存中分配系统全局区(SGA), 构成了Oracle的内存结构,然后启动若干个常驻内存的操作系统进程,即组成了Oracle的 进程结构,内存区域和后台进程合称为一个Oracle实例。
SGA是一组为系统分配的共享的内存结构,可以包含一个数据库实例的数据或控制信息。如果多个用户连接到同一个数据库实例,在实例的SGA中,数据可以被多个用户共享。 当数据库实例启动时,SGA的内存被自动分配;当数据库实例关闭时,SGA内存被回收。
SGA区是可读写的。所有登录到实例的用户都能读取SGA中的信息,而在oracle做执行操作时,服务进程会将修改的信息写入SGA区。
数据缓冲(Buffer Cache)
重做日志缓冲(Redo Log Buffer)
共享池(Shared Pool)
Java池(Java Pool)
大池(Large Pool)
流池(Streams Pool --- 10g以后才有)
数据字典缓存(Data Dictionary Cache)
其他信息(如数据库和实例的状态信息)
SQL> show sga
Total System Global Area 612368384 bytes
Database Buffers 411041792 bytes
Redo Buffers 7135232 bytes
SGA 中的 和会被实例的后台进程所访问,它们在实例启动后就固定在SGA中了,而且不会改变,所以这部分又称为
Shared Pool、Java Pool、Large Pool和Streams Pool这几块内存区的大小是相应系统参数设置而改变的,所以有通称为
通过下面的语句查询
SQL> show parameter sga
NAME TYPE VALUE
------------------------------------ ----------- -------
lock_sga boolean FALSE
pre_page_sga boolean FALSE
sga_max_size big integer 584M
sga_target big integer 584M
先对这几个参数做一下说明:
SQL>
NAME VALUE ISSYS_MOD
--------------- --------------- ---------
sga_max_size 612368384 FALSE
sga_target 612368384 IMMEDIATE
如果ISSYS_MODIFIABLE 返回的是false,说明该参数无法用alter system语句动态修改,需要重启数据库。
SGA区包括了各种缓冲区和内存池,而大部分都可以通过特定的参数来指定他们的大小。但是,作为一个昂贵的资源,一个系统的物理内存大小是有限。尽管对于CPU的内存寻址来说,是无需关系实际的物理内存大小的,但是过多的使用虚拟内存导致page in/out,会大大影响系统的性能,甚至可能会导致系统crash。所以需要有一个参数来控制SGA使用虚拟内存的最大大小,这个参数就是SGA_MAX_SIZE。
当实例启动后,各个内存区只分配实例所需要的最小大小,在随后的运行过程中,再根据需要扩展他们的大小,而他们的总和大小受到了SGA_MAX_SIZE的限制。
当试图增加一个内存的大小,并且如果这个值导致所有内存区大小总和大于SGA_MAX_SIZE时,oracle会提示错误,不允许修改。
当然,如果在设置参数时,指定区域为spfile时(包括修改SGA_MAX_SIZE本身),是不会受到这个限制的。这样就可能出现这样的情况,在spfile中,SGA各个内存区设置大小总和大于SGA_MAX_SIZE。这时,oracle会如下处理:当实例再次启动时,如果发现SGA各个内存总和大于SGA_MAX_SIZE,它会将SGA_MAX_SIZE的值修改为SGA各个内存区总和的值。
对于OLTP系统,一般的建议是将SGA_MAX_SIZE 设为物理内存的60%,PGA 设为20%。 但是现在服务器内存是相当大的。 几百G的内存随处可见。60%也就是几百G内存。 显然这样也是不合适的。 所以要根据自己系统来设定设定这个值。这个也就所说的DBA的经验。 这是是需要经验的积累。
下表的几个数值供参考。
系统内存
SGA_MAX_SIZE值
1G
400-500M
2G
1G
4G
2500M
8G
5G
SGA实际大小 = DB_CACHE_SIZE + DB_KEEP_CACHE_SIZE + DB_RECYCLE_CACHE_SIZE + DB_nk_CACHE_SIZE + SHARED_POOL_SIZE + LARGE_POOL_SIZE + JAVA_POOL_SIZE + STREAMS_POOL_SIZE(10g中的新内存池) + LOG_BUFFERS+11K(Redo Log Buffer的保护页) + 1MB + 16M(SGA内部内存消耗,适合于9i及之前版本)
oracle实例启动时,会只载入各个内存区最小的大小。而其他SGA内存只作为虚拟内存分配,只有当进程touch到相应的页时,才会置换到物理内存中。我们可以通过设置PRE_PAGE_SGA参数,让实例一启动后,所有SGA都分配到物理内存。
。当设置为TRUE时,实例启动会将全部SGA置入物理内存中。它可以使实例启动达到它的最大性能状态,但是,启动时间也会更长(因为为了使所有SGA都置入物理内存中,oracle进程需要touch所有的SGA页)。
SQL> alter system set pre_page_sga=true scope=spfile;
为了保证SGA都被锁定在物理内存中,而不必页入/页出,可以通过参数LOCK_SGA来控制。这个参数默认值为FALSE,当指定为TRUE时,可以将全部SGA都锁定在物理内存中。当然,有些系统不支持内存锁定,这个参数也就无效了。
Oracle10g中引入的一个非常重要的参数。在10g之前,SGA的各个内存区的大小都需要通过各自的参数指定,并且都无法超过参数指定大小的值,尽管他们之和可能并没有达到SGA的最大限制。此外,一旦分配后,各个区的内存只能给本区使用,相互之间是不能共享的。拿SGA中两个最重要的内存区Buffer Cache和Shared Pool来说,它们两个对实例的性能影响最大,但是就有这样的矛盾存在:在内存资源有限的情况下,某些时候数据被cache的需求非常大,为了提高buffer hit,就需要增加Buffer Cache,但由于SGA有限,只能从其他区“抢”过来——如缩小Shared Pool,增加Buffer Cache;而有时又有大块的PLSQL代码被解析驻入内存中,导致Shared Pool不足,甚至出现4031错误,又需要扩大Shared Pool,这时可能又需要人为干预,从Buffer Cache中将内存夺回来。
10g 以后有了新特性:。而控制这一特性的,也就。设置这个参数后,就不需要为每个内存区来指定大小了。SGA_TARGET指定了SGA可以使用的最大内存大小,而SGA中各个内存的大小由Oracle自行控制,不需要人为指定。Oracle可以随时调节各个区域的大小,使之达到系统性能最佳状态的个最合理大小,并且控制他们之和在SGA_TARGET指定的值之内。如果不设置SGA_TARGET,则自动共享内存管理功能被禁止。
共享池(Shared Pool)
Java池(Java Pool)
大池(Large Pool)
数据缓存区(Buffer Cache)
流池(Streams Pool)
对于SGA_TARGET的限制,它的大小是不能超过SGA_MAX_SIZE的大小的。
SGA_TARGET,它的值可以动态修改(在SGA_MAX_SIZE范围内)。在10g之前,如果需要修改SGA的大小(即修改SGA_MAX_SIZE的值)需要重启实例才能生效。当然,在10g中,修改SGA_MAX_SIZE的值还是需要重启的。但是有了SGA_TARGET后,(我个人不推荐频繁修改SGA的大小,SGA_TARGET在实例启动时设置好,以后不要再修改)。
SGA_TARGET带来一个重要的好处就是,能使SGA的利用率达到最佳,从而节省内存成本。因为ASMM启动后,Oracle会自动根据需要调整各个区域的大小,大大减少了某些区域内存紧张,而某些区域又有内存空闲的矛盾情况出现。这也同时大大降低了出现4031错误的几率。