内存结构是Oracle数据库体系结构中最为重要的部分之一,内存也是影响数据库性能的主要因素。在Oracle数据库中,服务器内存的大小将直接影响数据库的运行速度,特别是多个用户连接数据库时,服务器必须有足够的内存支持,否则有的用户可能连接不到服务器,或查询速度明显下降。
当用户发出一条SQL语句时,首先由服务器进程对用户的SQL语句进行语法分析并执行,然后将数据从数据文件读入到系统的数据缓冲区,修改后的数据由于服务器进程写回到数据文件中。按照系统对于内存的使用方法不同,Oracle数据库的内存可以分为系统全局区(SGA)、程序全局区(PGA)、排序区(SORT AREA)、大池(LARGE POOL)及Java池(Java POOL),如下图:
![图 9. Oracle 内存架构和后台进程](https://i-blog.csdnimg.cn/blog_migrate/77586fc5f936f6a615756f71a7df0be7.png)
Oracle内存结构
1 系统全局区
系统全局区(SGA)是一组为系统分配的共享的内存结构,可以包含一个数据库实例的数据或控制信息。如果多个用户连接到同一个数据库实例,则在实例的SGA中数据可为多个用户共享。在数据库实例启动时,SGA的内存被自动分配;当数据库实例关闭时,SGA被回收。SGA按其作用不同,可以分为数据缓冲区、日志缓冲区和共享池。
- 数据缓冲区
数据缓冲区用于存储从磁盘数据文件读取的数据,并为所有用户所其享。当用户向数据库请求数据时,如果所需的数据已经位于数据缓冲区,则Oracle将直接从数据缓冲区提取数据并返回组用户,而不必再从数据库文件中读取数据。
当用户第一次执行查询或修改数据操作时,服务器进将所需的数据从数据文件中读取出来,并装入到数据缓冲区中,这样数据的操作就可以在内存中完成。当用户下一次访问相同的数据时,Oracle就不必再从数据文件中读取数据,而可以直接将数据缓存区中的数据返回给用户。由于访问内存的速度要比访问磁盘快许多倍,这样可以极大地提高数据库对用户请示的响应速度。
数据缓冲区由许多相同大小的缓存块组成,这些缓存块的大小于数据块的大小相同。根据缓冲块是否被使用,可以将数据缓冲区中的缓冲块分为如下三类:
l 脏缓存块 脏缓存块中保存的数据为已经被修改过的数据,这些数据需要重新被写入到数据文件中。当一条SQL语句对某些缓存块中的数据修改后,这些缓存块将被标记为脏。然后等待DBWR进程写回数据文件。
l 空闲缓存块 空闲缓存块中不包含任何数据,它们等待向其写入数据。
l 命中缓存块 命中缓存块是那些正在被用户访问的缓存块,这些缓存块将被保留在数据缓冲区中。
Oracle通过两个列表来管理数据缓冲区中的缓存块。这两个列表分别是:写入列表(DIRTY)和最近最少使用列表(LRU)。这两个列表的作用如下:
l LRU LRU列表包含所有的空闲缓存块、命中缓存块以及脏缓存块。LRU列表使用LRU算法,将数据缓冲中那些最近一段时间内访问次数最少的缓存块将被移出缓冲区,这样要可以保证最频繁使用的块被保留在内存中,而将不必要的数据移出缓冲区。
l DIRTY 脏列表包含那些已经被修改并需要重新写入数据文件的缓存块。
数据缓冲区的工作过程如下:
当某个用户进程需要访部某些数据块时,Oracle首先在数据缓冲区中查找,如果该进程所需要的数据块已经位于数据缓冲区中,Oracle将直接从内存中读取数据并返回给用户,这种情况称为“缓存命中”。反之,如果在数据库缓冲区中找不到所需的数据块,Oracle必须先从数据文件中将所需的数据块复制到缓存中。然后再从缓存中读取它返回给用户,这种情况称为“缓存失败”。如果发生缓存失败,在将数据文件中的数据复制到缓冲区之前,必须首先找到空闲缓存块。Oracle将从LRU列表中查找空闲缓存块,如果没有空闲块,则将LRU列表中的脏缓存块移入到DIRTY列表中。当DIRTY超过一定长度时,再由DBWR将脏缓存块中的数据写入到磁盘数据文件中,重新刷新数据缓冲区,最后再将磁盘数据文件中的数据读出存入到数据缓冲区。
在Oracle8i以前的版本中,数据缓存的大小由DB_BLOCK_SIZE和DB_BLOCK_BUFFERS两个参数决定。其中DB_BLOCK_SIZE参数用于决定数据块的大小;而DB_BLOCK_BUFFERS参数用于设置数据缓冲区所包含的缓存块的数量。这样,数据缓冲区的大小就为这两个参数的乘积。在Oracle 9i后,数据缓存的大小可以直接由参数DB_CACHE_SIZE指定,该参数可以直接以KB或MB为单位来设置数据缓存的大小。
数据缓冲区对数据库的存取速度有直接的影响。如果数据缓冲区设置的过小,则缓存失败的机率将增大,这将影响数据库的响应速度,特别是用户较多尤为明显。因此如果能够使用更大的数据库缓存,就可以明显提高数据库的访问性能。但是系统的物理内存是有限的,如果将有限的物理内存全部分配给数据库缓存,则会影响到操作系统和数据库其他方面的性能。因此,在调整数据缓冲区时,需要权衡利弊设置适当的数据缓冲区大小。
- 日志缓冲区
日志缓冲区用于存储数据库的修改信息。当日志缓冲区的日志信息达到一定的数量时,由日志写入进程LGWR将日志信息定入日志文件组。
日志缓冲区是一个循环缓冲区,在使用时从顶端向底端写入数据,当到达日志缓冲区的最底端时,再返回到缓冲区的起始点循环写入。
日志缓冲区的大小由LOG_BUFFER参数指定,该参数也可以在数据库运行过程中动态修改。相对于数据缓冲区而言,日志缓冲区的大小对数据库性能的影响较小。通常较大的日志缓冲区能够减少日志文件的I/O次数,提高数据库的性能。
- 共享池
共享池是用于缓存与SQL或PL/SQL语句、数据字典、资源锁以及其他控制结构相关的数据。在共享池中主要包括库缓冲、数据字典缓冲,以及用户全局区3部分。库缓冲区含有SQL语句的分析码、执行计划;数据字典缓冲包含了从数据字典中得到的表、列定义和权限。用户全局区则包含用户的会话信息。共享池的总容量由SHARED_POOL_SIZE参数设定。
共享池中的库缓冲区用于缓存已经解析并执行过的 SQL 和 PL/SQL 程序代码。其主要作用是用来提高 SQL 或 PL/SQL 程序的执行效率。当一条 SQL 语句提交时, Oracle 首先在共享池的库缓冲区内进行搜索,查看相同的 SQL 语句是否已经被解析并执行。如果存在, Oracle 将利用缓冲区中的 SQL 语法分析结果和执行计划来执行该语句,而不必重新解析。使用缓冲区中的解析代码可以明显提高 SQL 和 PL/SQL 程序的执行速度。
在数据库的运行过程中,Oracle会频繁地对数据字典进行访问。为了提高访问率效,Oracle在共享池的数据字典缓冲区中保存了最常使用的数据字典信息。
2 程序全局区
程序全局区(PGA)是包含单独用户或服务器数据和控制信息的内存区域。PGA是在用户连接到Oracle数据库,并创建一个会话时,由Oracle自动分配的。与SGA不同,PGA是非共享区,只有服务进程本身才能访问它自己的PGA区,每个服务进程都有它自己的PGA区。各个服务进程在各自的PGA区中保存自身所使用到的各种数据。PGA的内容与结构和数据库的操作模式有关,在专用服务器模式下和共享服务器模式下,PGA有着不同的结构和内容。
-
排序区
排序区用于为排序显示的SQL语句提供内存空间,系统使用专门的内存区域进行数据的排序,这部分空间称为排序区。在Oracle数据库中,用户数据的排序有两个区域,一个是内存排序区,另一个是磁盘临时段。在排序区能够满足要求的情况下,系统将优先使用排序区,如果内存不够,Oracle将自动使用磁盘临时表空间进行排序。使用排序区可以显著提高排序操作的速度。排序区的大小由参数SORT_AREA_SIZE设置。
-
大池
大池是数据库管理员能够配置的可选内存空间,可以用于不同类型的内存存储。在执行某些特定类型的操作时,可能需要在内存中使用大量的缓存,这些特定类型的操作包括:
l 数据库的备份或恢复操作。
l 执行具有大量排序操作的SQL语句。
l 执行并行化的数据库操作。
如果没有创建大池,则上述操作所需的缓存空间将在共享池或PGA中分配。由于这些操作将占用大量的缓存空间,因此会影响到共享池或PGA的使用效率。大池的大小通过LAGE_POOL_SIZE参数指定。如果数据库处理共享服务器操作模式下,服务器进程就会将它们的会话数据存储在大池中,而不是共享池中。当会话结束后,大池就会释放内存以使其他会话使用。
-
Java池
由于Oracle提供了对Java语言的支持,所以系统提供了Java池。Java池主要用于为Java语言提供语法分析区。Java池的大小由参数JAVA_POOL_SIZE确定。