在 32 位的操作系统上, Oracle 系统理论上可以使用的内存上限是 4G ,即 2^32 字节,任何多出的部分, Oracle 均不会使用;在 64 位的操作系统上, Oracle 系统可以使用的内存理论上是 2^64 字节,在可以预见的未来的应用,这几乎和没有上限限制是一样的。因此在购买小型机服务器硬件设备时(一般都会自带操作系统)要考虑到使用的是多少位的操作系统,否则即使内存配得再多,也不会给性能带来提高。在使用 32 位的操作系统时,如果该服务器设备专门用作数据库服务器(即不在其上安装其它诸如应用服务器等软件)时,配置 6G 的内存应该是比较恰当的,除 4G Oracle 使用外, 2G 内存用来运行操作系统本身的进程。
注意 1 :如果是 UNIX Linux32 位操作系统,还要设置操作系统级的参数 shmmax SGA 的空间可以大于 shmmax ,具体情况请参考 Oracle 安装手册以及操作系统手册 ;
注意 2: 本小节(下面)中所列的操作可能需要一定的权限,在实际工作中,如果发现相关权限的问题,请及时给相关用户授权或以一个权限更大的用户的身份进行操作。
       Oracle 总体内存结构如下图所示:
 Oracle系统参数优化
从上图中, Oracle 的内存结构主要有 SGA PGA 组成,其中 UGA 的一部分为 SGA 所管理,而另一部分则为 PGA 所管理, CGA 则不关 UGA SGA 管理还是被 PGA 所管理,它总是处于 UGA 之内。
 
或许由于 SGA 太重要了,以致大家忽略了 PGA UGA CGA 的存在。比如很多人都搞不清楚 PGA UGA 两者之间的区别,实际上两者之间的区别跟一个进程和一个会话之间的区别是类似的。尽管说进程和会话之间一般都是一对一的关系,但实际上比这个更复杂。一个很明显的情况是 MTS 配置,会话往往会比进程多得多。在这种配置下,每一个进程会有一个 PGA ,每一个会话会有一个 UGA PGA 所包含的信息跟会话是无任何关联的,而 UGA 包含的信息是以特定的会话为基础的。现在我们对 PGA UGA CGA 做以下介绍:
 
进程全局区 (PGA) 即可以理解为 Process Global Area ,也可以理解为 Program Global Area 。它的内存段是在进程私有区 (Process Private Memory) 而不是在共享区 (Shared Memory) 。它是个全局区意味着它包含了所有代码有可能进入的全局变量和数据结构,但是它是不被所有进程共享的。每个 Oracle 的服务器进程都包含有属于自己的 PGA ,它只包含了本进程的相关特定信息。 PGA 中的结构不需要由 latches 来保护,因为其它的进程是不能进入到这里面来访问的。 PGA 包含的是有关进程正在使用的操作系统资源信息以及进程的状态信息,而其它的进程所使用的 Oracle 的共享资源是在 SGA 中。 PGA 是私有的而不是共享的,这个机制是有必要的,因为当进程死掉后可以把这些资源清除和释放掉。 PGA 包含两个主要区域: Fixed PGA Variable PGA 或称为 PGA Heap Fixed PGA 的作用跟 Fixed SGA 是类似的,都包含原子变量 ( 不可分的 ) ,小的数据结构和指向 Variable PGA 的指针。 Variable PGA 是一个堆。它的 Chunks 可以从 Fixed Table X$KSMPP 查看得到,这个表的结构跟前面有提到的 X$KSMSP 是相同的。 PGA HEAP 包含了一些有关 Fixed Table 的永久性内存,它跟某些参数的设置有依赖关系。这些参数包含 DB_FILES LOG_FILES CONTROL_FILES
 
UGA(User Global Area) 包含的是特定会话的信息,有如下一些 :
       所打开游标的持续和运行时间内的区域
       包的状态信息,特定的变量
       Java 会话状态
       可以用的 ROLES
       ENABLE 的跟踪事件
       起作用的 NLS 参数设置
       打开的 DBLINK
       会话的入口控制
PGA 一样, UGA 也由两区组成: Fixed UGA Variable UGA ,也称为 UGA HEAP Fixed UGA 包含了大约 70 个原子变量,小的数据结构和指向 Variable UGA 的指针。 UGA HEAP 中的 Chunks 可以从它们自己的会话中通过查看表 X$KSMUP 获得相关信息,这个表的结构跟 X$KSMSP 是一样的。 UGA HEAP 包含了一些有关 fixed tables 的永久性内存段,跟一些参数的设置有依赖关系。这些参数有 OPEN_CURSORS OPEN_LINKS MAX_ENABLE_ROLES
 
调用全局区 (CGA) 跟其它的全局区不同, Call Global Area 是短暂性存在的。它只有在调用数据期间存在,一般是在对实例的最低级别的调用时才需要 CGA ,如下:
       分析一个 SQL 语句
       执行一个 SQL 语句
       取出一个 SELECT 语句的输出
一个单独的 CGA 在递归调用时是需要的。在 SQL 语句的分析过程中,对数据字典信息的递归调用是需要的,因为要对 SQL 语句进行语法分析,还有在语句的优化期间要计算执行计划。执行 PL/SQL 块时在处理 SQL 语句的执行时也是需要递归调用的,在 DML 语句的执行时要处理触发器执行也是需要递归调用的。不管 UGA 是放在 PGA 中还是在 SGA 中, CGA 都是 PGA 的一个子堆 (Subheap) 。这个事实的一个重要推论是在一个调用的期间会话必须是一个进程。对于在一个 MTS Oracle 数据库进程应用开发时关于这一点的理解是很重要的。如果相应的调用较多,就得增加 processes 的数量以适应调用的增加。没有 CGA 中的数据结构, CALLS 是没法工作的。而实际上跟一次 CALL 相关的数据结构一般都是放在 UGA 中,如 SQL AREA PL/SQL AREA SORT AREA 它们都必须在 UGA 中,因为它们要在各 CALLS 之间要一直存在并且可用。而 CGA 中所包含的数据结构是要在一次 CALL 结束后能够释放的。例如 CGA 包含了关于递归调用的信息,直接 I/O BUFFER 等还有其它的一些临时性的数据结构。 Java Call Memory 也是在 CGA 中。这一段内存比 Oracle 的其它内存段管理得更密集。它分成三个 Space Stack Space New Space Old Space 。在 New Space Old Space 中不再被参考使用的 Chunks ,根据它们在使用期间的长度及 SIZE 的不同,在调用的执行过程中将被当成不用的 Chunks 收集起来。 New Space Chunks 很多次的不用的 Chunks 的反复收集过程中没有被收集的 Chunks 将会被放到 Old Space Chunks 中。这是在 Oracle 内存管理中唯一的一个废物收集 (garbage collection) ,其它的 Oracle 内存段都是释放 Dead Chunks
 
正象前面提到的, Oracle 数据库系统和信能相关最主要的就是 SGA System Global Area )了,它由 SHARED POOL DATABASE BUFFER CACHE Redo LOG BUFFER 三部分组成, 其中又以 SHARED POOL DATABASE BUFFER CACHE 对于日常碰到的系统性能调整最为重要。现在我们假定 Oracle 运行在 32 位的操作系统上,并且系统有足够多的内存可以分配,那么我们可以修改 sga_max_size ,使其等于 4G 60% (因为 PGA 也需要使用内存,并且它并未包含在 SGA 中),即:
       sga_max_size=2458M
 
调整 SHARED POOL 。在 SHARED POOL 中,又包含两个 CACHE ,即 Library Cache Data Dictionary Cache
Library Cache 用于存放共享 SQL 语句和 PL/SQL 语句,采用 LRU Least Recently Used )算法进行管理, Oracle 可以用已经 cache 在其中的 SQL 语句,而不需要 re-parsing ,我们可以通过下面的 SQL 语句来查询 Library Cache 的命中率( Hit Ratio ):
SQL> select GETHITRATIO
from v$librarycache
where NAMESAPCE 'SQL AREA';
如果得到的结果小于 90% ,那么说明命中率不高,需要增大 Library Cache 了。如果想要将某个 package 放于 Library Cache 中,请使用以下命令:
SQL> execute dbms_shared_pool.keep('package_name');
要将某个 package Library Cache 移出,请使用以下命令:
SQL> execute dbms_shared_pool.unkeep('package_name');
 
Data Dictionary Cache 主要用来保持字典对象的相关信息。可以查看视图 v$rowcache ,该视图由以下各列组成:
 列名 说明
 PARAMETERS 数据字典项的分类
 GETS 对于此类字典项的信息获取次数
 GETMISSES 对于此类字典项的信息获取失败次数
 
如果 GETMISSES/ GETS * 100% > 15% ,那么就要考虑增大 Data Dictionary Cache 了。
 
很重要地, Library Cache Data Dictionary Cache 不能单独进行调整,要对它们进行调整,只能通过调整 SHARED_POOL_SIZE 来进行( Oracle 会自动去分配 Library Cache Data Dictionary Cache 的大小,如何分配这个过程不被人控制)。比如,如果想增加 Library Cache ,那么请增加 SHARED_POOL_SIZE 。下面是分配 SHARED POOL 大小的经验公式:
SHARED_POOL_SIZE = sga_max_size * 40%
       在前面我们已经得出 sga_max_size 2458M 了,那么按照上面这个公式,
       SHARED_POOL_SIZE = 2458 * 40% 983M
 
调整 DATABASE BUFFER CACHE BUFFER CACHE 也是 SGA 的一部分,它主要保存可以被所有用户共享的数据块。用下面的 SQL 语句来检查 BUFFER CACHE 的命中率:
    SQL> select 1 – (phys.value/(cur.value + con.value)) "CACHE HIT RATIO"
                from v$sysstat cur, v$sysstat con, v$sysstat phys
                where cur.name = 'db block gets' and
                con.name = 'consistent gets' and
                phys.name = 'physical reads';
如果上面的命令的数据结果小于 80% ,那么就需要考虑增大 DATABASE BUFFER CACHE 了。在 Oracle9i 以前的版本,需要在 init<SID>.ora 中增加 DB_BLOCK_BUFFERS 的数值(因为数据库系统安装完成后 DB_BLOCK_SIZE 就固定了), DATABASE BUFFER CACHE 的容量= DB_BLOCK_BUFFERS * DB_BLOCK_SIZE ;在 Oracle9i 及其以后版本,则需要修改该 DB_CACHE_SIZE
 
       DATABASE BUFFER CACHE 的大小计算的经验公式:
       DATABASE BUFFER CACHE 的大小 = sga_max_size * 40%
       在前面我们已经得出 sga_max_size 2458M 了,那么按照上面这个公式,
       DATABASE BUFFER CACHE 的大小 = 2458 * 40% 983M
 
调整 PGA 大小。调整 PGA 的大小是通过设置 pga_aggregate_target 这个参数来实现的。设置此参数时, 要将 SGA 从可用于 Oracle 例程的系统内存总量中减去。然后可将剩余内存量分配给 pga_aggregate_target 。如果继续我们前面说到的情况,那么,
       pga_aggregate_target 4G 2458M 1638M
PGA 影响到的最主要是 sort_area_size hash_area_size 这两个参数,它们分别根据排序操作的多少 / 大小, hash_join 的多少 / 大小来决定的。在江钻现有的系统中,我们发现排序操作和 jion 的操作都有很多 ( 感觉上 join 操作比排序操作更多也更复杂 ) ,可以考虑以下的公式:
sort_area_size = pga_aggregate_target * 30%
hash_area_size pga_aggregate_target * 40%
 
其它参数调整。
db_file_multiblock_read_count 表明在涉及一个完全连续扫描的一次 I/O 操作过程中读取的块的最大数量,默认值是 8 。增加该值可以提高查询的速度,但取值到底是多大,要根据操作系统的情况来定,一般而言最好不要超过 32 (可在实际工作中反复试试,一遍确定一个最合理的值)。
 
java_pool_size 以字节为单位, 指定 Java 存储池的大小, 它用于存储 Java 的方法和类定义在共享内存中的表示法, 以及在调用结束时移植到 Java 会话空间的 Java 对象。如果没有使用 Oralce HTTP 之类的服务,令 java_pool_size = 64M 即可
 
large_pool_size 指定大型池的分配堆的大小,它可被共享服务器用作会话内存,用作并行执行的消息缓冲区以及用作 RMAN 备份和恢复的磁盘 I/O 缓冲区。一般可令 large_pool_size pga_aggregate_target * 10%
 
最后,我们必须要认识到系统参数调优的过程是一个比较复杂的过程,而且根据不同应用目的的系统各种参数的给定有非常大的差别,比如有些系统数据变化不是很频繁,主要用于查询,而另外一些系统主要用来插入数据,因此放之四海而皆准的方法或者经验公式是不存在的。尽管如此,一些经过许多人积累下来的方法或者经验公式还是提供了一个很好的出发点,在此基础上,通过反复试验,应该可以得到一组相对优化的参数取值。