1.6 Oracle内存结构
Oracle使用服务器的物理内存来保存Oracle实例的许多内容:Oracle的可执行代码自身、会话信息、与数据库关联的单独进程、进程之间共享的信息(如数据库对象上的锁)。此外,内存结构还包含用户和数据字典SQL语句,以及最终永久存储在磁盘上的缓存信息,如来自数据库段的数据块和数据库中已完成事务的相关信息。分配给Oracle实例的数据区域称为系统全局区域(System Global Area,SGA)。Oracle的可执行代码驻留在软件代码区域。此外,名为程序全局区域(Program Global Area,PGA)的区域对于每个服务器和后台进程来说都是私有的,Oracle为每个进程分配一个PGA。图1-5显示了这些Oracle内存结构之间的关系。
图1-5 Oracle逻辑内存结构
1.6.1 系统全局区域
系统全局区域是用于Oracle实例的一组共享内存结构,由数据库实例的用户共享。启动Oracle实例时,系统根据在初始参数文件中指定的值或在Oracle软件中硬编码的值,为SGA分配内存。控制SGA不同部分大小的许多参数都是动态的;然而,如果指定SGA_MAX_SIZE参数,则所有SGA区域的全部大小必须不能超出SGA_MAX_SIZE的值。如果没有指定SGA_MAX_SIZE,但指定了参数SGA_TARGET,Oracle就自动调整SGA各组成部分的大小,从而使分配的内存总量等同于SGA_TARGET。SGA_TARGET是动态参数,可在实例运行时改变。MEMORY_TARGET是Oracle 11g中新增的参数,用于在SGA和PGA(稍后讨论)之间平衡Oracle可用的所有内存,以优化性能。
SGA中的内存以“区组(granule)”为单位分配。区组的大小可为4MB或16MB,这取决于SGA的总体大小。如果SGA小于或等于128MB,区组就是4MB;否则,区组为16MB。
接下来将介绍Oracle如何使用SGA中每个部分的重点内容。第8章将介绍如何调整与这些区域关联的初始参数等更多信息。
1.缓冲区缓存
数据库缓冲区缓存(buffer cache)保存来自磁盘的数据块,这些数据块有的满足最近执行的SELECT语句,有的是通过DML语句改变或添加的已修改块。从Oracle 9i开始,SGA中保存这些数据块的内存区域是动态的。这样做有一定优点,因为它考虑到数据库中可能有一些表空间的块大小不同于默认块大小。最多有5种不同块大小(一种是默认块大小,最多具有其他4种块大小)的表空间需要自己的缓冲区缓存。因为处理和事务需要每日或每周改变,所以可动态改变DB_CACHE_SIZE和DB_nK_CACHE_SIZE的值,而不需要重新启动实例,从而获得比给定块大小的表空间更好的性能。
Oracle可使用两个具有相同块大小的额外缓存作为默认块大小(DB_CACHE_SIZE):KEEP缓冲池和RECYCLE缓冲池。从Oracle 9i开始,这些缓冲池独立于SGA中的其他缓存分配内存。
创建表时,通过在STORAGE子句中使用BUFFER_POOL_KEEP或BUFFER_POOL_RECYCLE子句,可指定表的数据块驻留在哪个缓冲池中。对于一天中频繁使用的表,最好将其放在KEEP缓冲池中,从而最小化检索表中数据块所需要的I/O。
2.共享池
共享池包含两个主要的子缓存:库缓存和数据字典缓存。共享池的大小由初始参数SHARED_POOL_SIZE确定。这也是一个动态参数,其大小可以调整,只要SGA的全部大小小于SGA_MAX_SIZE或SGA_TARGET即可。
库缓存 库缓存保存针对数据库运行的SQL和PL/SQL语句的有关信息。在库缓存中,因为由所有用户共享,所以许多不同的数据库用户可以潜在地共享相同的SQL语句。
和SQL语句自身一起,SQL语句的执行计划和解析树也存储在库缓存中。第二次由同一用户或不同用户运行同一条SQL语句时,由于已经计算了执行计划和解析树,因此可以提高查询或DML语句的执行速度。
如果库缓存过小,则必须将执行计划和解析树转储到缓存外面,这就需要频繁地将SQL语句重新加载到库缓存中。查看第8章可了解监控库缓存效率的方法。
数据字典缓存 数据字典是数据库表的集合,由SYS和SYSTEM模式拥有,其中包含有关数据库、数据库结构以及数据库用户的权限和角色的元数据。数据字典缓存保存第一次读到缓冲区缓存之后的数据字典表的列的子集。数据字典中来自表的数据块常用于辅助处理用户查询和其他DML命令。
如果数据字典缓存太小,对数据字典中信息的请求将造成额外的I/O。这些I/O绑定的数据字典请求称为“递归调用”,应该通过正确设置数据字典缓存的大小加以避免。
3.重做日志缓冲区
重做日志缓冲区保存对数据文件中的数据块所进行的最近的改动。当重做日志缓冲区的1/3已满或者每隔3秒时,Oracle将重做日志记录写入重做日志文件。从Oracle 10g开始,当重做日志缓冲区中存储了1MB重做信息时,LGWR进程就将重做日志记录写入重做日志文件。一旦将重做日志缓冲区中的条目写入重做日志文件,如果在将改动的数据块从缓冲区缓存写入数据文件之前实例崩溃,这些条目就对数据库恢复起着至关重要的作用。只有将重做日志条目成功写入重做日志文件后,才可以认为用户提交的事务完成。
4.大型池
大型池是SGA的可选区域,用于与多个数据库交互的事务、处理并行查询的消息缓冲区以及RMAN并行备份和还原操作。顾名思义,大型池可为需要一次分配大块内存的操作提供所需要的大块内存。
初始参数LARGE_POOL_SIZE控制大型池的大小,这是从Oracle 9i版本2开始新增的一个动态参数。
5.Java池
Oracle的Java虚拟机(Java Virtual Machine,JVM)使用Java池来处理用户会话中的所有Java代码和数据。将Java代码和数据存储在Java池中类似于将SQL和PL/SQL代码缓存在共享池中。
6.流池
流池是Oracle 10g中新增的池,使用初始参数STREAMS_POOL_SIZE可以确定其大小。流池保存用于支持Oracle企业版中Oracle流特性的数据和控制结构。Oracle流管理分布式环境中数据和事件的共享。如果初始参数STREAMS_POOL_SIZE未初始化或者将其设置为0,则从共享池中分配用于流操作的内存,并且最多可以分配共享池10%的容量。第17章将介绍关于Oracle流的更多信息。
1.6.2 程序全局区域
程序全局区域(Program Global Area,PGA)是分配给一个进程并归该进程私有的内存区域。PGA的配置取决于Oracle数据库的连接配置:共享服务器或专用服务器。
在共享服务器配置中,多个用户共享一个数据库连接,从而最小化服务器上的内存使用率,但可能影响对用户请求的响应时间。在共享服务器环境中,由SGA而不是PGA来保存用户的会话信息。对于大量同时进行,伴有很少发生的请求或短期请求的数据库连接,共享服务器是理想的环境。
在专用服务器环境中,每个用户进程获得自己的数据库连接,PGA包含这种配置的会话内存。
PGA也包括一个排序区域,当用户请求需要排序、位图合并或散列连接操作时,就会使用这种排序区域。
从Oracle 9i开始,通过PGA_AGGREGATE_TARGET参数和WORKAREA_SIZE_POLICY初始参数的结合,DBA可选择所有工作区域的全部大小,并让Oracle管理并分配所有用户进程之间的内存,从而简化系统管理。如前所述,MEMORY_TARGET参数作为一个整体管理PGA和SGA内存来优化性能。
1.6.3 软件代码区域
软件代码区域存储作为Oracle实例的一部分运行的Oracle可执行文件。这些代码区域实际上是静态的,只有在安装软件的新版本时才会改变。一般来说,Oracle软件代码区域位于与其他用户程序隔离的权限内存区域。
Oracle软件代码是严格只读的代码,可共享安装或非共享安装。当多个Oracle实例运行在同一服务器上和相同的软件版本级别时,按可共享方式安装Oracle软件代码可节省内存。
1.6.4 后台进程
当Oracle实例启动时,多个后台进程就会启动。后台进程是设计用于执行特定任务的可执行代码块。图1-6显示了后台进程、数据库和Oracle SGA之间的关系。与SQL*Plus会话或Web浏览器等前台进程不同,用户无法看到后台进程的工作情况。SGA和后台进程结合起来组成了Oracle实例。
图1-6 Oracle后台进程
1.SMON
SMON是系统监控器(System Monitor)进程。在系统崩溃或实例故障的情况下,由于停电或CPU故障,通过将联机重做日志文件中的条目应用于数据文件,SMON进程可执行崩溃恢复。此外,它在系统重新启动期间清除所有表空间中的临时段。
SMON的一个常规任务是定期合并字典管理的表空间中的空闲空间。
2.PMON
如果删除用户连接,或者用户进程以其他方式失败,PMON(也称为“进程监控器”)就会进行清除工作。它清除数据库缓冲区缓存以及用户连接所使用的其他任何资源。例如,用户会话可能正在更新表中的某些行,在一行或多行上放置锁。一场雷雨袭击了用户办公桌的电力设置,当工作站的电源关闭时,SQL*Plus会话消失。期间,PMON将检测到连接不再存在,并执行下面的任务:
●回滚到电源断开时正在处理的事务。
●在缓冲区缓存中标记可用的事务块。
●删除表中受影响的行上的锁。
●从活动进程列表中删除未连接进程的进程ID。
通过将实例状态的相关信息提供给传入的连接请求,PMON也和监听器交互。
3.DBWn
数据库写入程序(database writer)进程,在Oracle的旧版本中也称为DBWR,负责将缓冲区缓存中新增的或改动的数据块(称为“脏块”)写入数据文件。使用LRU算法,DBWn首先写入最早的、最小的活动块。因此,请求最多的块位于内存中,即使它们是脏块。
最多可启动20个DBWn进程,DBW0~DBW9,以及DBWa~DBWj。通过DB_WRITER_PROCESS参数可以控制DBWn进程的数量。
4.LGWR
LGWR,或称为“日志写入程序”进程,负责管理重做日志缓冲区。在具有大量DML活动的实例中,LGWR是最活跃的进程之一。直到LGWR成功地将重做信息(包括提交记录)写入重做日志文件,才能认为事务已经完成。此外,直到LGWR已经写入重做信息,才可以通过DBWn将缓冲区缓存中的脏缓冲区写入数据文件。
如果分组重做日志文件,并且组中一个多元复用的重做日志文件已经受损,LGWR将写入剩余的组成员,并在警报日志文件中记录错误。如果组中的所有成员都不可用,LGWR进程就会失败,并且整个实例挂起,直至问题得到纠正为止。
5.ARCn
如果数据库处于ARCHIVELOG模式,只要重做日志填满并且重做信息开始按顺序填充下一个重做日志,归档程序进程(ARCn)就将重做日志复制到一个或多个目的地目录、设备或网络位置。最理想的情况下,归档进程应在下一次使用填满的重做日志之前完成。否则会产生严重的性能问题:将条目写入重做日志文件前用户无法完成他们的事务,而重做日志文件还没有准备好接受新条目,因为它仍在写入归档位置。对于该问题,至少有3种可能的解决方案:使重做日志文件更大一些,增加重做日志组的数量,增加ARCn进程的数量。针对每个实例最多可启动30个ARCn进程,其方法是增加LOG_ARCHIVE_MAX_ PROCESSES初始参数的值。
6.CKPT
检查点进程(checkpoint process),即CKPT,可帮助减少实例恢复所需要的时间。在检查点期间,CKPT更新控制文件和数据文件的标题,从而反映最近成功的系统变更号(System Change Number,SCN)。每次进行重做日志文件切换时,都自动生成一个检查点。DBWn进程按常规写入脏缓冲区,将检查点从实例恢复可以开始的位置提前,从而减少平均恢复时间(Mean Time to Recovery,MTTR)。
7.RECO
RECO即恢复器进程(recoverer process),用于处理分布式事务(即包括对多个数据库中的表进行改动的事务)的故障。如果同时改变CCTR数据库和WHSE数据库中的表,而在可以更新WHSE数据库中的表之前,两个数据库之间的网络连接失败了,RECO将回滚失败的事务。