
2.4 Oracle数据库内存结构
Oracle的内存结构由两大部分组成,一个是SGA,另一个是PGA。PGA称为程序全局区,程序全局区不是实例的一部分,当服务器进程启动时,才分配PGA。而SGA称为系统全局区,它是数据库实例的一部分,当数据库实例启动时,会首先分配系统全局区,在系统全局区中包含几个重要的内存区,即数据库高速缓存(Database buffer cache)、重做日志缓存(Redo log buffer cache)、共享池(Shared pool)、大池(Large pool)和Java池(Java pool)。接下来的几个小节中将详细介绍Oracle数据库的内存结构。
2.4.1 共享池(shared pool)
Oracle引入共享池的目的就是共享SQL或PL/SQL代码,即把解析得到的SQL代码的结果在这里缓存,其中PL/SQL代码不仅在这里缓存,同时也在这里共享。共享池由两部分组成(如图2-5所示),即库高速缓存和数据字典高速缓存。

图2-5 共享池的组成
1.库高速缓存
库高速缓存存储了最近使用过的SQL和PL/SQL语句。当然它的容量是有限的,Oracle采用一种LRU(least recently used)算法管理库高速缓存,该算法的基本思想是把一段时间内没有被使用过的语句清除,一旦缓冲区填满,算法把最近最少使用的执行计划和解析树从库高速缓存中清除。显然库高速缓存设置得越大,就可以共享的SQL或PL/SQL代码就越多,但是Oracle并没有设计直接设置库高速缓存的指令,只能通过设置共享池的大小间接地更改,而共享池是SGA的一部分,所以共享池不能超过SGA的大小,如下面例子所示设置共享池大小。
例子2-2 设置共享池的大小
SQL> alter system set shared_pool_size = 16M; 系统已更改。 通过例子2.3验证修改结果。
例子2-3 查看共享池的大小
SQL> show parameter shared_pool_size; NAME TYPE VALUE ------------------------------------ ----------- --------------------------------------- shared_pool_size big integer 16777216
2.数据字典高速缓存
顾名思义,该缓存区是与数据字典相关的一段缓冲区。在数据字典高速缓冲区中存储了数据文件、表、索引、列、用户、权限信息和其他一些数据库对象的定义。在SQL语句的解析阶段,数据库服务器需要这些信息来解析用户名和用户的访问权限。如果Oracle缓存了这些信息,无疑相应地提高了查询时间。
数据字典缓存也称为字典缓存或者行缓存,无论称呼如何,它的作用就是把相关的数据字典信息放入缓存以提高查询的响应时间。
同样数据字典高速缓存的大小取决于共享池尺寸的大小。如果设置的太小,当查询需要数据字典信息时,Oracle将通过不断地访问数据字典表来获得所需的信息,由于数据字典也是存储在磁盘上的一类数据文件,频繁的磁盘I/O无疑降低了数据库的查询速度。如果需要设置字典高速缓存的大小,需要通过设置shared_pool_size间接实现。
2.4.2 数据库高速缓冲区(database buffer cache)
数据库高速缓冲中存储了最近从数据文件读入的数据块信息或用户更改后需要写回数据库的数据信息,此时这些没有提交给数据库的更改后的数据称为脏数据。当用户执行查询语句,如select * from dept时,如果用户查询的数据块在数据库高速缓存中,Oracle就不必从磁盘读取,而可以直接从数据库高速缓存中读取,显然物理读取的速度比从内存读取的速度慢很多,这些缓存的数据由LRU算法管理。可见Oracle设计各种缓存的目的基本相同,就是提高查询速度,减少用户的查询响应时间。Oracle使用LRU算法管理库缓冲区,把最近没被使用的数据库从库高速缓存中删除,为其他的查询数据块保留空间。
Oracle使用参数DB_BLOCK_SIZE和DB_BLOCK_BUFFERS设置库高速缓存的大小,DB_BLOCK_SIZE是Oracle数据块的大小,而DB_BLOCK_BUFFERS是数据库的个数,二者的乘积就是库高速缓存的大小。例子2-4为查询Oracle数据块的大小。
例子2-4 查看数据块大小
SQL> show parameter db_block_size; NAME TYPE VALUE --------------------------------------------------------- ------------------- -------------- db_block_size integer 8192
注意
用这种方式设置数据库高速缓存的大小需要重启数据库才能生效,db_block_size的值是8192字节(即8K字节)。
在Oracle9i及以上版本中提供了一个DB_CACHE_SIZE参数来设置Oracle数据库高速缓存区的大小,该参数可以动态更改,之后可以通过查询指令查看更改后的参数。
接下来用例子2-5说明查询Oracle11g中数据库高速缓存的大小。
例子2-5 查询数据库高速缓存的大小
SQL> show parameter db_cache_size; NAME TYPE VALUE -------------------------------------------------------- ------------------- ----------------- db_cache_size big integer 0
因为在Oracle11g中,SGA为数据库服务器自动管理,所以该参数值为0,当然在运行Oracle11g数据库时,数据库高速缓存一定是已分配好的,我们使用show sga指令查看数据库高速缓冲区分配的内存大小,如例子2-6所示。
例子2-6 查询数据库高速缓存的大小
SQL> show sga; Total System Global Area 535662592 bytes Fixed Size 1334380 bytes Variable Size 260047764 bytes Database Buffers 268435456 bytes Redo Buffers 5844992 bytes
说明
上述指令查询SGA的分配情况,其中Database Buffers为数据库缓存区的大小。我们更改的值为32M,而显示的值为33554432字节,二者一致,说明修改成功(32M=32*1024*1024bytes=33554432 bytes)。
虽然在Oracle11g中数据库高速缓存的大小自动管理,但是用户可以设置该数据库组件的大小,如例子2-7所示。
例子2-7 动态设置数据库高速缓冲区大小
SQL> alter system set db_cache_size = 200M; 系统已更改。
在Oracle中引入了Buffer Cache Advisory Parameter参数,其目的是让Oracle对于数据库缓冲区的内存分配提供一些建议。
下面介绍缓冲区顾问参数(Buffer Cache Advisory Parameter)的作用,缓冲区顾问用于启动或关闭统计信息,这些信息用于预测不同缓冲区大小导致的不同行为特性。对于DBA可以参考这些统计信息,基于当前的数据库工作负载,设置优化的数据库高速缓存。
缓存顾问通过初始化参数DB_CACHE_ADVICE启动或关闭顾问功能,该参数有以下三个状态。
● OFF:关闭缓存顾问,不分配缓存顾问的工作内存。
● ON:打开缓存顾问,分配工作内存。
● READY:打开缓存顾问,但不分配缓存顾问的工作内存。
例子2-8 当前缓存顾问的状态
NAME TYPE VALUE -------------------------------------------------------- ------------------ ----------------- db_cache_advice string ON
在上述输出中可以看出,参数db_cache_advice的值为ON,所以默认是打开缓存顾问的。例子2-9演示了如何设置缓存顾问为关闭状态,其实就是通过设置参数db_cache_advice实现的。
例子2-9 关闭数据库高速缓存顾问
SQL> alter system set db_cache_advice = off; 系统已更改。
在更改了缓存顾问状态后,通过例子2-10查看当前的缓存顾问状态,以验证更改结果。
例子2-10 查看数据库高速缓存顾问状态
SQL> show parameter db_cache_advice; NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ db_cache_advice string OFF
当然我们的目的是使用缓存顾问,所以需要再次将参数db_cache_advice的值设置为ON,如下例所示。
SQL> alter system set db_cache_advice = on; 系统已更改。
在设置顾问缓存为开启状态后,Oracle开始统计与设置数据库缓存相关的建议信息,可以通过动态性能视图v$DB_CACHE_ADVICE查看缓冲区的建议信息,如例子2-11所示。
例子2-11 查看与设置数据库高速缓冲区相关的信息
SQL> col id for 99 SQL> SELECT id, name, block_size, size_for_estimate, buffers_for_estimate 2 FROM v$db_cache_advice; ID NAME BLOCK_SIZE ADV SIZE_FOR_ESTIMATE BUFFERS_FOR_ESTIMATE -- ---------------- -------------------- ---------- --- ----------------- ---------------------------------------- 3 DEFAULT 4096 ON 3.0703 786 3 DEFAULT 4096 ON 6.1406 1572 3 DEFAULT 4096 ON 9.2109 2358 3 DEFAULT 4096 ON 12.2813 3144 3 DEFAULT 4096 ON 15.3516 3930 3 DEFAULT 4096 ON 18.4219 4716 3 DEFAULT 4096 ON 21.4922 5502 3 DEFAULT 4096 ON 24.5625 6288 3 DEFAULT 4096 ON 27.6328 7074 3 DEFAULT 4096 ON 30.7031 7860 3 DEFAULT 4096 ON 33.7734 8646 ID NAME BLOCK_SIZE ADV SIZE_FOR_ESTIMATE BUFFERS_FOR_ESTIMATE -- ---------------- -------------------- ---------- --- ---------------------- ---------------------------------------- 3 DEFAULT 4096 ON 36.8438 9432 3 DEFAULT 4096 ON 39.9141 10218 3 DEFAULT 4096 ON 42.9844 11004 3 DEFAULT 4096 ON 46.0547 11790 3 DEFAULT 4096 ON 49.125 12576 3 DEFAULT 4096 ON 52.1953 13362 3 DEFAULT 4096 ON 55.2656 14148 3 DEFAULT 4096 ON 58.3359 14934 3 DEFAULT 4096 ON 61.4063 15720 已选择20行。
2.4.3 重做日志高速缓冲区(redo buffer cache)
当用户执行了如INSERT、UPDATE、DELETE、CREATE、ALTER和DROP操作后,数据会发生变化,这些变化了的数据在写入数据库高速缓存之前会先写入重做日志缓冲区,同时变化之前的数据也放入重做日志高速缓存,这样在数据恢复时Oracle就知道哪些需要前滚哪些需要后滚。
重做日志缓冲区的大小是可以动态调节的,即在数据库运行期间修改这块内存的大小,Oracle提供了一个初始化参数LOG_BUFFER,在数据库实例启动时就分配好重做日志缓冲区的尺寸。例子2-12演示了如何查看重做日志缓存区。
例子2-12 查看重做日志缓存区
SQL> show parameter log_buffer; NAME TYPE VALUE -------------------------------------------------------- ------------------- -------------
说明
重做日志缓存区参数log_buffer是静态参数,不能动态修改。如果尝试修改,会提示如下错误。
log_buffer integer 5653504 SQL> alter system set log_buffer = 1M; alter system set log_buffer = 1M * ERROR 位于第 1 行: ORA-02095: 无法修改指定的初始化参数
2.4.4 大池(large pool)和Java池
大池是SGA的一段可选内存区,只在共享服务器环境中配置大池(large pool)。在共享服务器环境下,Oracle在共享池中分配额外的空间用于存储用户进程和服务器进程之间的会话信息,但是用户进程区域UGA(可理解为PGA在共享服务器中的另一个称呼)的大部分将在大池中分配,这样就减轻了共享池的负担。在大规模输入、输出及备份过程中也需要大池作为缓存空间。
Oracle提高了参数large_pool_size设置大池的尺寸。下面使用例子2-13查看大池的尺寸。
例子2-13 查看大池大小
SQL> show parameter large_pool_size NAME TYPE VALUE --------------------------------------------------------- ------------------ ------------ large_pool_size big integer 52M
参数large_pool_size是动态参数,可以通过alter system指令修改该参数的值,语句格式为:
“alter system set large_pool_size = 48M;”。
Java池也是可选的一段内存区,但是在安装Java或者使用Java程序时,则必须设置Java池,它用于编译Java语言编写的指令。Java语言与PL/SQL语言在数据库中有相同的存储方式。Oracle提供了参数Java_pool_size设置Java池的大小。使用例子2-14查看当前Java池的大小。
例子2-14 查看Java池的大小
SQL> show parameter java_pool_size; NAME TYPE VALUE ---------------------------------------------------- ------------- java_pool_size big integer 0
说明
在Oracle11g中,Java池大小由数据库服务器在SGA中自动分配,当然用户也可以使用alter system指令修改该参数的值,在例子2.14中参数Java_pool_size的值为0,说明该参数为自动管理。
2.4.5 流池(Streaming pool)
流池也称为流内存,它是为Oracle流专用的内存池,流(Stream)是Oracle数据库中的一个数据共享,其大小可以通过参数stream_pool_size动态调整。
2.4.6 PGA(进程全局区)和UGA(用户全局区)
进程全局区(PGA)是服务器进程专用的一块内存,它是操作系统进程专用的内存,系统中的其他进程是无法访问这块内存的。PGA独立于SGA,PGA不会在SGA中出现,它是由操作系统在本地分配的。
1.PGA(进程全局区)
PGA中存储了服务器进程或单独的后台进程的数据信息和控制信息。它随着服务器进程的创建而被分配内存,随着进程的终止而释放内存。PGA与SGA不同,它不是一个共享区域,而是服务器进程专有的区域。在专有服务器(与共享服务器相对的概念)配置中包括如下的组件:
● 排序区:对某些的SQL语句执行结果进行排序。
● 会话信息:包含本次会话的用户权限和性能统计信息。
● 游标状态:标明当前会话执行的SQL语句的处理阶段。
● 堆栈区:包含其他的会话变量。
注意
在共享服务器配置中,多个用户进程共享一个服务器进程,上述的一些内存区可能在SGA中分配。如果创建了大池(large pool),这些内存结构就存储在大池中,否则它们存储在共享池中。
图2-6和图2-7分别是专有服务器模式和共享服务器模式下的PGA结构图。

图2-6 专有服务器模式下的PGA结构

图2-7 共享服务器模式下的PGA结构
注意
在共享服务器结构中,会话信息是存储在SGA中的,两种模式下堆栈区(Stack space)都存储在PGA中。
2.UGA(用户全局区)
在共享服务器模式下有一个重要的概念,即UGA(用户全局区),它表示用户的会话状态,这部分内存会话总可以访问,UGA存储在每个共享服务器都可以访问的SGA中,这样任何服务器都可以使用用户会话的数据和其他信息。而在专有服务器模式下,用户会话状态不需要共享,用户进程与服务器进程是一一对应的关系,所以UGA总是在PGA中分配。
3.PGA内存管理
从Oracle9i开始,Oracle提供了两种方法管理PGA,即手动PGA管理和自动PGA管理。采用手动管理时,必须告诉Oracle一个特定的进程需要的排序区,允许使用多少内存。而在自动PGA管理中,则要求高速Oracle在系统范围内可以为PGA中的特定功能(如排序区)分配多少内存。例子2-15显示了笔者计算机上PGA中排序区的大小。
例子2-15 查询PGA中排序区的大小
SQL> show parameter sort_area_size; NAME TYPE VALUE --------------------------------------------------------- ------------------ ---------------- sort_area_size integer 65536
在服务器进程最初查询时,会使用512KB内存实现数据排序,在Oracle将排序数据处理完之前,数据排序区的大小就由参数SORT_AREA_SIZE决定。
注意
在Oracle10g和Oracle11g中可以实现共享服务器连接时PGA的自动管理,而在Oracle9i中,使用共享服务器连接时,只能使用手动PGA管理。
2.4.7 如何获得内存缓冲区的信息
SGA是Oracle中所有进程共享的一段内存区,其中共享了数据库信息,如数据库高速缓冲区中的数据、共享池中的库、高速缓存中的SQL语句等。了解这些内存缓冲区的大小有助于理解Oracle的内存分配情况。例子2-16为查看数据库的SGA(系统全局区)。
例子2-16 查看SGA中内存的分配情况
SQL> show sga; Total System Global Area 535662592 bytes Fixed Size 1334380 bytes Variable Size 260047764 bytes Database Buffers 268435456 bytes Redo Buffers 5844992 bytes
在上述输出中可以看到,SGA、Database Buffers和Redo Buffers 的尺寸,前面已经讲解了这些内存组件的作用。读者或许注意到了Fixed Size和Variable Size这两个参数,它们和两个内存区有关,下面解释这两个内存区。
● 和fixed size相关的内存区:在固定的SGA中,存储一组指向SGA中其他组件的变量。它的大小因平台不同而有差异,用户无法控制,但通常固定SGA 区很小。Oracle使用这个内存区来寻找其他SGA区,可以理解为数据库的自举区。
● 和Variable Size相关的内存区:该部分内存区包括共享池、Java池和大池,其中Variable Size的尺寸要高于上述三个内存结构之和,因为在Total SGA中除去的db_cache_size部分也包括在Variable Size中。
同时读者也可以参照例子2-17查询当前数据库的SGA尺寸。
例子2-17 查看SGA的尺寸
SQL> show parameter sga_max_size; NAME TYPE VALUE ------------------------------------------------------ --------------------- ------------------ sga_max_size big integer 512M
说明
在Oracle11g中该参数的值得到修正而以M字节作为单位,更利于识别,而在Oracle10g版本中参数sga_max_size的值以字节为单位。