1.1.3 Oracle内存结构

Oracle使用服务器的物理内存来保存Oracle实例的很多信息:Oracle可执行代码本身、会话信息、与数据库关联的各个进程以及进程之间共享的信息(例如数据库对象上的锁)。另外,内存结构包含用户和数据字典SQL语句,以及最终永久存储在磁盘上的缓存信息,如数据库段中的数据块以及有关数据库中已完成事务的信息。为Oracle实例分配的数据区域称为系统全局区(System Global Area, SGA)。Oracle可执行文件位于软件代码区域。另外,称为程序全局区(Program Global Area, PGA)的区域专供每个服务器和后台进程使用;为每个用户会话或服务器进程分配一个PGA。

图1-3显示这些Oracle内存结构之间的关系。

图1-3 Oracle逻辑内存结构

1.系统全局区

SGA是Oracle实例的一组共享内存结构,由数据库实例的多位用户共享。启动Oracle实例时,会根据初始化参数文件中指定的值或Oracle软件中的硬编码为SGA分配内存。用于控制SGA各个部分大小的很多参数是动态的(可在实例运行时立即改变);但是,如果指定SGA_MAX_SIZE参数,所有SGA区域的总大小就不得超过SGA_MAX_SIZE的值。如果未指定SGA_MAX_SIZE,但指定了SGA_TARGET参数,Oracle会自动调整SGA组件的大小,以便分配的内存总量等于SGA_TARGET。SGA_TARGET是一个动态参数,可在实例运行时更改。Oracle 11g中引入的新参数MEMORY_TARGET在SGA和PGA之间平衡Oracle的所有可用内存,以便优化性能。

SGA中的内存按粒度单元分配。粒度可以是4MB或16MB,具体取决于SGA的总大小。如果SGA小于等于128MB,则粒度是4MB;否则粒度是16MB。随后几节将介绍Oracle如何使用SGA中的每个部分的要点。

缓冲区缓存(Buffer Cache) 数据库缓冲区缓存保存最近从磁盘读取的用于满足SELECT语句要求的数据块,或包含已修改块(已经从DML语句更改或添加)的数据块。从Oracle Database 9i开始,SGA中保存这些数据块的内存区域是动态的。这是一件好事,假如数据库的多个表空间的块大小不是默认块大小。Oracle允许表空间最多使用5种不同的块大小(一种块大小是默认的,其余类型的最多有4种)。每个块大小都需要自己的缓冲区缓存。如果一天或一周中处理和事务需求发生了变化,将可以动态更改DB_CACHE_SIZE和DB_nK_CACHE_SIZE的值而无须重新启动实例,以便提高使用给定块大小的表空间的性能。

Oracle可以使用其他两种块大小与默认块大小(DB_CACHE_SIZE)相同的缓存:KEEP缓冲区池和RECYCLE缓冲区池。从Oracle Database 9i开始,这两个池都独立于SGA中的其他缓存分配内存。

创建表时,可以通过在STORAGE子句中使用BUFFER_POOL_KEEP或BUFFER_POOL_RECYCLE子句,来指定表的数据块将要驻留的池。对于整天频繁使用的表,有利的做法是将表放在KEEP缓冲区池中,以尽量减少检索表中的块需要的I/O数量。

共享池(Shared Pool) 共享池包含两个主要的子缓存:库缓存和数据字典缓存。共享池的大小由SHARED_POOL_SIZE初始化参数确定。只要SGA总大小小于SGA_MAX_SIZE或SGA_TARGET,这便是另一种可以调整大小的动态参数。

库缓存保存有关针对数据库运行的SQL和PL/SQL语句的信息。库缓存由所有用户共享,所以不同数据库用户可能共享同一SQL语句。

SQL语句及其执行计划存储在库缓存中。当同一用户或另一用户第二次运行同一SQL语句时,由于已经计算出执行计划,查询或DML语句的执行效率将会提高。

如果库缓存过小,则可以将频繁使用的执行计划转出缓存,只需频繁地将SQL语句重新加载到库缓存中。

数据字典是数据库表的集合,归SYS和SYSTEM模式所有,其中包含有关数据库、数据库结构以及数据库用户权限和角色的元数据。数据字典缓存保存第一次将数据字典表读入缓冲区缓存后数据字典表的列的子集。连续使用数据字典中的表的数据块,以便帮助处理用户查询和其他DML命令。

如果数据字典缓存过小,在请求数据字典中的信息时,会引发附加的I/O操作;这些与I/O相关的数据字典请求称为“递归调用”,可通过正确设置数据字典缓存的大小来避免“递归调用”。

重做日志缓冲区 重做日志缓冲区包含数据文件中的数据块的最新更改信息。如果重做日志缓冲区的满度达到1/3(或每隔3秒),Oracle会将重做日志记录写入重做日志文件中。另外,从Oracle Database 10g开始,如果已将1MB重做信息存储在重做日志缓冲区中,Log Writer(日志写入器,LGWR)进程会将重做日志记录写入重做日志文件中。一旦将重做日志缓冲区中的条目写入重做日志文件,那么,如果在将更改后的数据块从缓冲区缓存写入数据文件前实例发生了崩溃,这些条目对恢复数据库会起到至关重要的作用。在将重做日志条目成功写入重做日志文件后,才认为用户提交的事务是完整的。

大池(Large Pool) 大池是SGA中的可选区域。它用于与多个数据库交互的事务、执行并行查询的进程的消息缓冲区,以及RMAN并行备份和还原操作。顾名思义,大池使需要每次分配大内存块的操作可以使用大内存块。

初始化参数LARGE_POOL_SIZE控制大池的大小,该参数是一个动态参数。

Java池(Java Pool) Oracle JVM(Java Virtual Machine, Java虚拟机)为用户会话中的所有Java代码和数据使用Java池。在Java池中存储Java代码和数据与在共享池中缓存SQL和PL/SQL代码是相似的。

流池(Streams Pool) 从Oracle 10g开始,通过初始化参数STREAMS_ POOL_SIZE来设置其大小。流池保存数据和控制结构,以便支持Oracle Enterprise Edition的Oracle流功能。Oracle流管理分布式环境中数据和事件的共享。如果未初始化STREAMS_ POOL_SIZE初始化参数或将其设置为0,则从共享池分配流操作使用的内存,内存占用量最多可达共享池的10%。

2.程序全局区

PGA(Program Global Area,程序全局区)专门用于一组相互联系的进程,是自行分配动态部分的内存区域。PGA的配置取决于Oracle数据库的连接配置:共享服务器或专用服务器。

在共享服务器配置中,多个用户共享与数据库的连接,此时,对服务器的内存使用量降至最低,但用户请求的响应时间可能受到影响。在共享服务器环境中,SGA(而非PGA)保存用户的持久会话信息。如果同时有大量用户连接到数据库,请求频率不高或时间短,那么共享服务器环境就是理想环境。

在专用服务器环境中,每个用户进程独自连接到数据库,PGA中包含此配置的会话内存。PGA中还包含一个排序区域,如果用户请求需要排序、位图归并或散列连接操作,将使用此区域。

从Oracle Database 9i开始,PGA_AGGREGATE_TARGET参数连同WORKAREA_SIZE_POLICY初始化参数一起允许DBA选择所有工作区的总大小,并使Oracle在所有用户进程间分配和管理内存,以此来简化系统管理工作。如本章前面所述,MEMORY_TARGET参数从总体上管理PGA和SGA内存以便优化性能,该参数可以帮助从总体上管理PGA和SGA的大小调整。简而言之,PGA在Oracle 9i中实现了自动化,而SGA在10g中实现了自动化。从Oracle 11g起,SGA和PGA作为一个整体实现了自动化。即使经验丰富的DBA也会发现,使用自动化的内存结构,可以更有效地管理内存分配。

3.软件代码区

软件代码区存储作为Oracle实例一部分运行的Oracle可执行文件。这些代码区域本质是静态的,只有在安装新软件版本时才会发生变化。Oracle软件代码区通常位于享有特权的内存区,此内存区与其他用户程序分开放置。

Oracle软件代码完全是只读的,可按共享或不共享形式进行安装。如果以共享形式安装Oracle软件代码,当多个Oracle实例在同一软件版本级别和相同服务器上运行时,可以节省内存。

4.后台进程

启动Oracle实例时,会启动多个后台进程。后台进程是一个用于执行特定任务的可执行代码块。图1-4显示后台进程、数据库和Oracle SGA之间的关系。与前台进程(如SQL*Plus会话或Web浏览器)形成对照,后台进程在后台运行。SGA与后台进程共同构成了Oracle实例。

图1-4 Oracle后台进程

SMON 如果由于断电或CPU故障导致系统崩溃或实例故障,那么SMON(system monitor,系统监视器)进程通过将联机重做日志文件中的条目应用于数据文件,在崩溃后执行恢复。另外,在重新启动系统时,会清除所有表空间中的临时段。

如果表空间由字典管理,则SMON的一个例行任务是定期组合表空间中的可用空间(在Oracle Database或12c数据库中,这种情况很少出现或根本不存在)。

PMON 如果用户连接断开或用户进程失败,那么PMON(process monitor,进程监视器)将执行清理工作。它清除数据库缓冲区缓存以及用户连接曾使用的其他任何资源。例如,假如一个用户会话正在更新一个表中的一些行,在一行或多行上设置了锁。用户桌面突然断电,在工作站断电时SQL*Plus会话消失。PMON会在数毫秒内检测到连接不再存在,并执行以下任务:

●回滚断电时正在进行的事务。

●在缓冲区缓存中将事务的块标记为可用。

●从表中受影响的行上删除锁。

●从一系列活动进程中删除断开连接的进程的进程ID。

PMON通过提供有关传入连接请求的实例的状态信息与侦听器进行交互。

DBWn 早期Oracle版本的数据库写入器(database writer, DBWR)进程将缓冲区缓存中的新数据块或更改过的数据块(称为脏块)写入数据文件中。使用LRU(Least Recently Used,最近最少使用)算法,DBWn首先写入时间最早、活动性最差的块。结果,最常请求的块(即使是脏块)会在内存中。

最多可以启动100个DBWn进程,DBW0到DBW9、DBWa到DBWz,以及BW36到BW99。DBWn进程的数量由DB_WRITER_PROCESSES参数控制。

LGWR LGWR(Log Writer,日志写入器)负责管理重做日志缓冲区。在DML活动频繁的实例中,LGWR是活动最密集的进程之一。在LGWR将重做信息(包括提交记录)成功写入重做日志文件后,才认为事务已经完成。另外,在LGWR写入重做信息后,DBWn才能将缓冲区缓存中的脏缓冲区写入数据文件中。

如果将重做日志文件分组,而且一个组中的多路复用重做日志文件受损,LGWR会写入到组中的其余成员中,并在警报日志文件中记录错误。如果组中所有成员均不可用,将造成LGWR进程失败,在更正问题前,整个实例将挂起。

ARCn 如果数据库处于ARCHIVELOG模式,那么,归档程序进程(archiver process, ARCn)会在重做日志填满然后开始将重做信息顺序填充到下一个重做日志中时,将重做日志复制到一个或多个目标目录、设备或网络位置。理想情况下,归档进程会在归档下一个填满的重做日志前完成。否则会发生严重的性能问题:在条目写入重做日志文件前,用户无法完成事务,而重做日志文件无法接受新条目,因为正在将其写入到归档位置。至少可以采用3种可能解决该问题的方案:增加重做日志文件的大小、增加重做日志组的数量和增加ARCn进程的数量。通过增加LOG_ARCHIVE_MAX_PROCESSES初始化参数的值,可以为每个实例启动更多ARCn进程,启动的ARCn进程的最大数量是10个。

CKPT 检查点(checkpoint process, CKPT)进程有助于减少恢复实例的用时。执行检查点期间,CKPT更新控制文件和数据文件的头,以便反映最后的成功系统更改编号(System Change Number, SCN)。每次填满一个重做日志文件,Oracle开始循环填充下一个日志文件时,会自动执行检查点操作。

DBWn进程不时写入脏缓冲区,以便前移作为恢复实例开始位置的检查点,减少平均恢复时间(Mean Time to Recovery, MTTR)。

RECO 恢复程序进程(recoverer process, RECO)处理分布式事务(更改多个数据库的表)的故障。如果CCTR(contact center,联系中心)数据库中的一个表以及WHSE(数据仓库)数据库中的一个表都发生了变化,而且数据库之间的网络连接在更新WHSE数据库的表之前出现故障,那么,RECO将回滚此失败的事务。