
第4章 Oracle体系结构
4.1 内存结构
Oracle服务器由Oracle实例和Oracle数据库两部分组成。而Oracle实例又由后台进程和共享内存组成,所以Oracle的结构又包含了内存结构和进程结构;而Oracle数据库由物理文件和逻辑结构组成,所以Oracle结构也包含了物理存储结构和逻辑存储结构。
Oracle内存结构是由SGA和PGA两大部分组成的。要设置内存结构的总大小可以通过修改MEMORY_TARGET初始化参数来实现,但是MEMORY_TARGET初始化参数的值不能大于MEMORY_MAX_TARGET初始化参数。
4.1.1 系统全局区
系统全局区(System Global Area,SGA)是一块容量较大的共享的内存结构,包含一个Oracle实例的数据或控制信息,可以被Oracle服务器进程和后台进程所共享使用。当Oracle实例启动时,SGA的内存会被自动分配。当Oracle实例关闭时,SGA的内存会被回收。
因为Oracle 11G中使用自动共享内存管理(Automatic Shared Memory Management,ASMM),可以自动调整SGA中各内存组件的大小。只需要设置SGA_TARGET初始化参数,则其他组件就能够根据Oracle的负载和历史信息自动地调整各个部分的大小。SGA_TARGET初始化参数的值不能大于SGA_MAX_SIZE初始化参数。
SGA结构如图4-1所示。

图4-1 SGA结构
1. 数据库缓冲区高速缓存
数据库缓冲区高速缓存(Database Buffer Cache)也称为缓冲区高速缓存(Buffer Cache),是由许多小缓冲区组成的,其主要作用是缓存最近访问的数据块信息,Oracle数据库中对数据的所有修改操作都是在该内存中进行的。数据库的所有操作都必须先将物理文件上的数据块读取到数据库缓冲区高速缓存中,然后才能进行各种操作。数据库缓冲区高速缓存的大小可以通过DB_CACHE_SIZE初始化参数来进行设置。
Oracle 11G还提供了可以设置多种数据块大小(2、4、8、16或32)的数据库缓冲区高速缓存,以便存储不同数据块大小的表空间中的对象。使用DB_nk_CACHE_SIZE初始化参数来指定不同数据块大小的数据库缓冲区高速缓存,这里的n就是2、4、8、16或32。创建数据库时,使用DB_BLOCK_SIZE初始化参数指定默认的标准数据块尺寸,标准数据块尺寸用于SYSTEM表空间。然后可以指定最多4个不同的、非标准数据块尺寸的表空间。每种数据块尺寸的表空间必须对应一种不同尺寸的数据库缓冲区高速缓存,否则不能创建不同数据块尺寸的表空间。
(1)缓冲区状态
数据库使用内部算法在数据库缓冲区高速缓存中管理缓冲区。
缓冲区可以是以下任何一种状态。
➢ 未使用(Unused):表示缓冲区从未被使用或当前未使用,缓冲区可供使用。这种类型的缓冲区是数据库中最容易使用的。
➢ 干净(Clean):表示块中包含的数据是干净的,所以它并不需要被执行检查点,数据库可以固定该块并重用它。
➢ 脏(Dirty):表示缓冲区包含还没有被写入磁盘文件的修改数据。
(2)缓冲池
缓冲池是缓冲区的集合,可以在数据库缓冲区高速缓存中配置多个缓冲池,以便实现在数据库缓冲区高速缓存中保留数据,或使数据缓冲区在其中的数据块被使用后可以立即写入新数据。用户可以指定方案对象使用相应的缓冲池。
数据库缓冲区高速缓存可以分为以下3种缓冲池。
➢ DEFAULT池(Default Pool):它是一个必须要存在的缓冲池,池中存储的是没有被指定使用其他缓冲池的方案对象的数据,以及被显式地指定使用DEFAULT池的方案对象的数据。如果不是人为设置初始化参数,Oracle将默认使用DEFAULT池。用于配置DEFAULT池大小的初始化参数为DB_CACHE_SIZE。
➢ KEEP池(Keep Pool):它是一个可选缓冲池,用于保存那些经常被访问的对象,主要目的是将方案对象的数据一直保留在内存中,从而避免I/O操作。用于配置KEEP池大小的初始化参数为DB_KEEP_CACHE_SIZE。
➢ RECYCLE池(Recycle Pool):它是一个可选缓冲池,用于存储不常使用的大表,将随时清除存储在RECYCLE池中不再被用户需要的数据。RECYCLE池防止对象在缓存中占用不必要的空间。用于配置RECYCLE池大小的初始化参数为DB_RECYCLE_CACHE_SIZE。
注意
KEEP池和RECYCLE池只能使用标准块大小。
2. 重做日志缓冲区
重做日志缓冲区(Redo Log Buffer)是一个SGA中的循环缓冲区,用于按顺序存储对数据库所做更改的重做条目的描述,然后LGWR后台进程会将重做日志缓冲区中的记录写到联机重做日志文件中。重做日志缓冲区用于记载实例的变化,在执行DDL或DML语句时,服务器进程首先将事物的变化记载到重做日志缓冲区,然后才会修改数据库缓冲区高速缓存。
重做日志缓冲区由许多重做记录(Redo Record)组成,并且每条重做记录记载了被修改数据块的位置以及变换后的数据。
重作日志缓冲区可以加快数据库的操作速度,但是考虑到数据库的一致性与可恢复性,数据在重做日志缓冲区中的滞留时间不会很长。重做日志缓冲区的大小可以通过LOG_BUFFER初始化参数来进行设置。
3. 共享池
共享池(Shared Pool)是SGA中最重要的内存区域,主要用于提高SQL和PL/SQL语句的执行效率,包括执行计划及运行SQL语句的语法分析树。在第二次运行相同的SQL语句时,可以利用共享池中可用的语法分析信息来加快执行速度。共享池的大小可以通过SHARED_POOL_SIZE初始化参数来进行设置。
共享池通过LRU(最近最少使用)算法来进行管理。当共享池存满时,将从库缓存中删除LRU的执行路径和语法分析树,以便为新的条目腾出空间。如果共享池太小,SQL语句将被连续不断地再装入库缓存,从而影响操作性能。
共享池的结构如图4-2所示。

图4-2 共享池结构
(1)库缓存
库缓存(Library Cache)用于存储最近执行的SQL和PL/SQL语句的信息,包括SQL语句文本、解析代码值和执行计划,以及PL/SQL语句的代码块、执行码等。当用户提交一个SQL语句时,Oracle会将这条SQL语句进行分析,会耗费比较多的时间。在分析完这个SQL语句以后,Oracle会把分析结果保存在共享池的库缓存中,当数据库第二次执行该SQL语句时,Oracle自动跳过这个分析过程,从而减少了系统运行的时间。
库缓存是存储可执行的SQL和PL/SQL代码共享池的内存结构,包含共享SQL和PL/SQL区以及控制结构,比如锁和库缓存处理。在共享服务器体系结构中,库缓存中还包含专用SQL区。
(2)数据字典缓存
数据字典缓存(Data Dictionary Cache)用于存储在编译SQL和PL/SQL语句时参照的数据字典的信息,其大小是动态变化的,不是固定的。在语法分析阶段,服务器进程会在数据字典中查找用于对象解析和验证访问的信息。将数据字典信息高速缓存到内存中,可以缩短数据查询和DML操作的响应时间。
(3)服务器结果缓存
服务器结果缓存(Server Result Cache)用来保存结果集,而不是数据块。服务器结果缓存包含SQL查询结果缓存和PL/SQL函数结果缓存,它们共享相同的架构。
(4)保留池
保留池(Reserved Pool)用来保留一部分内存空间以备需要时使用。通常情况下,Oracle会将大的内存请求分割成小的内存块来满足需求。而对于大的内存且为连续的内存空间请求,如果在共享池中未找到,则会动用共享池中的保留池。共享池在内存压力的情况下,也会使用保留池中的部分。保留池部分能更高效地满足较大的内存需求。默认情况下,Oracle会配置较小的保留池,这部分可以用于PL/SQL、触发器编译或用于装载Java对象的临时空间。这些分配出去的内存一旦释放后将返回给保留池。
保留池大小不能超过共享池的50%,一般情况下建议为共享池的5%~10%。保留池的大小可以通过SHARED_POOL_RESERVED_SIZE初始化参数来进行设置。
4. 大池
大池(Large Pool)是一个可选的内存池,供一次性大量的内存分配使用,为共享SQL分配会话内存,数据库避免了因收缩共享SQL缓存的性能开销。通过为RMAN操作、I/O服务器进程、并行缓冲区分配内存,大池比共享池更好地满足大内存要求。
大池的主要作用是分担共享池的一部分工作。某些情况(如RMAN备份恢复)如果没有分配大池,则会从共享池中分配内存,这样会增加共享池的负担。大池的大小可以通过LARGE_POOL_SIZE初始化参数来进行设置。与共享池相同,大型池不使用LRU列表管理其中内存的分配与回收。
5. Java池
Java池(Java Pool)是用于存储所有特定于会话的Java代码和Java虚拟机(JVM)内数据的内存区域。Java池的大小可以通过JAVA_POOL_SIZE初始化参数来进行设置。
6. 流池
流池(Streams Pool)存储缓冲队列消息,并为Oracle流捕获进程和应用进程提供内存。流池是数据库在流工作时使用的内存区域,为Oracle流专用。除非特别配置,流池的大小从零开始。所要求的Oracle流池的大小动态地增长。流池的大小可以通过STREAMS_POOL_SIZE初始化参数来进行设置。
4.1.2 程序全局区
程序全局区(Program Global Area,PGA)是一个用于存储服务器进程的数据和控制信息的内存区域,当用户连接到Oracle服务器时,Oracle服务器会为每个服务器进程分配相应的PGA。一个PGA也只能被拥有它的服务器进程所访问,只有这个进程中的Oracle代码才能读写它。要设置PGA的总大小可以通过修改PGA_AGGREGATE_TARGET初始化参数来实现。
PGA主要包含排序区、会话区、堆栈区和游标区4个部分,以此完成用户进程和数据库之间的会话。
1. 排序区
当用户需要对某些数据进行排序时,首先会将需要排序的数据保存到PGA中的排序区内,然后再在排序区内对这些数据进行排序。如果需要排序的数据有4MB,那么排序区内必须至少要有2MB的空间来容纳这些数据。然后排序过程中又需要有4MB的空间来保存排序后的数据。由于Oracle从内存中读取数据比从硬盘中读取数据的速度要快很多倍,因此如果这个数据排序与读取的操作都能够在内存中完成,无疑可以在很大程度上提高数据库排序和访问的性能。在数据库管理中,如果发现用户的很多操作都需要用到排序,那么设置一个比较大的排序区,可以提高用户访问数据的效率。
在Oracle数据库中,排序区主要用来存放排序操作产生的临时数据,排序区的大小占据PGA的大部分空间,这是影响PGA大小的主要因素。在小型数据库应用中,可以直接采用其默认的值。但是在一些大型的数据库应用中,或者需要进行大量记录排序操作的数据库系统中,可以手工调整排序区的大小,以提高排序的性能。如果需要调整排序区大小,可以通过修改SORT_AREA_SIZE初始化参数来实现。
2. 会话区
会话区内保存了连接会话所具有的权限、角色和性能统计等信息,大部分情况下用户不需要维护会话区,可以让Oracle自动进行维护。当用户进程与数据库建立会话时,Oracle会将这个用户的相关权限查询出来,然后保存在会话区内。用户进程在访问数据时,Oracle就会核对会话区内的用户权限信息,查看其是否具有相关的访问权限。由于Oracle将这个用户的权限信息存放在内存上,所以其核对用户权限的速度非常快。Oracle不用再从硬盘中读取数据,而直接从内存中读取,而从内存读取数据的效率要比硬盘快很多。
3. 游标区
游标区是一个动态的区域,当用户执行游标语句时,Oracle会在程序缓存区中为其分配游标区。当关闭游标时,这个区域就会被释放。创建和释放这个区域需要占用一定的系统资源,花费一定的时间。如果频繁地打开和关闭游标,就会降低语句的执行性能。游标用来完成一些比较特殊的功能,采用游标的语句要比其他语句的执行效率低一点。
在Oracle数据库中,还可以通过限制游标的数量来提高数据库的性能,如在Oracle中设置OPEN_CURSORS初始化参数,控制用户能够同时打开游标的数目。在确实需要游标的情况下,如果硬件资源能够支持,那么就需要放宽这个限制。这可以避免用户进程频繁地打开和关闭游标。因为频繁地打开和关闭游标对游标的操作是不利的,会影响数据库的性能。
4. 堆栈区
为了提高SQL语句的重用性,会在语句中使用绑定变量,使得SQL语句可以接受用户传入的变量。从而用户只需要输入不同的变量值,就可以满足不同的查询需求,如现在用户需要查询所有员工的信息,然后又要查询所有工龄在3年以上的员工,此时其实他们采用的是同一个SQL语句,只是传递给系统的变量不同而已。这可以在很大程度上降低数据库开发的工作量。这个变量在Oracle数据库中就叫做绑定变量。利用绑定变量可以加强与用户的互动性。另外在这个堆栈区内还保存着会话变量、SQL语句运行时的内存结构等重要的信息。
通常情况下,堆栈区和会话区一样,都可以让Oracle根据实际情况来进行自动分配,而不需要用户进行维护。当这个用户会话结束时,Oracle会自动释放堆栈区所占用的空间。