武警单杠1至9全套视频:Oracle 概念(Oracle 10.2) 第八章 内存结构

来源:百度文库 编辑:中财网 时间:2024/05/07 10:00:18
8、内存结构
这一章描述了Oracle实例的内存结构。
本章包含下列主题:
u Oracle内存结构介绍
u 系统全局区(SGA)概述
u 程序全局区(PGA)概述
u 专用和共享服务器
u 软件代码区域
Oracle内存结构介绍
Oracle使用内存保存下列信息:
u 程序代码
u 连接会话的信息,即使是非活动会话
u 程序执行时需要的信息(例如,一个获取行的查询的当前状态)
u 在Oracle进程之间共享和通讯的信息(例如,锁信息)
u 在外部存储中持久保存的缓存数据(例如,数据块和重做日志条目)
Oracle相关基础内存结构包括:
u 系统全局区(SGA),在所有服务器进程和后台进程之间共享
u 程序全局区(PGA),对于每个服务器进程和后台进程私有的区域,每个进程都有一个PGA。
图8-1 描述了这些内存结构的联系。
图8-1 Oracle内存结构

软件代码区域是另外一个基本内存区域。
系统全局区(SGA)概述
系统全局区(SGA)是包含Oracle数据库实例的数据和控制信息的一组共享内存结构。如果多个用户并发连接同一个实例,那么实例的SGA数据在用户之间共享。所以,SGA有时候叫做共享全局区。
SGA和Oracle进程构成了一个Oracle实例。Oracle在你启动实例时,自动为SGA分配内存,在你关闭实例时,操作系统释放内存。每个实例都有它自己的SGA。
SGA是可读写的。连接到多进程数据库实例的所有用户可以读取实例SGA中的信息,Oracle运行时多个进程写数据到SGA。
SGA包含下列数据结构:
u 数据库高速缓存(Database buffer cache)
u 重做日志缓存(Redo log buffer)
u 共享池(Shared pool)
u Java池(Java pool)
u 大池(Large pool,可选)
u 流池(Streams pool)
u 数据字典缓存(Data dictionary cache)
u 其他信息
SGA包含数据库和实例的通用信息,后台进程需要访问这部分信息;这部分叫做固定(fixed)SGA。这里不保存用户数据。SGA还包括进程之间通讯的信息,比如锁信息。
如果系统使用共享服务器架构,那么请求和回应队列和PGA的一些内容保存在SGA中。
初始化参数:SGA_MAX_SIZE
SGA由多个内存组件组成,这些内存是池化的,满足特定类型的内存分配需求。内存组件的例子包括共享池(用来对执行的SQL和PL/SQL分配内存)、Java池(Java对象和其他Java执行需要的内存)、高速缓存(buffer cache,用来缓存磁盘块)。所有的SGA组件按照一个固定的单位(颗粒,granules)来分配和释放空间。Oracle数据库使用针对每个SGA组件使用内部的颗粒数量来跟踪SGA内存。
颗粒尺寸由整体SGA大小决定。在大多数平台,如果总体SGA尺寸小于1GB,颗粒大小为4M,更大的SGA颗粒尺寸是16M。某些平台会略有不同。例如,在32位的windows平台上,SGA尺寸大于1G时,颗粒大小为8M。
Oracle可以设置数据库SGA使用的虚拟内存的大小。它可以按最小内存启动实例,允许实例通过扩展SGA组件的内存分配来使用更多的内存,直到达到初始化参数SGA_MAX_SIZE的限制为止。如果初始化参数文件或服务器参数文件(SPFILE)定义的SGA_MAX_SIZE小于所有组件分配的内存之和(可以显式在参数文件中指定或者默认指定),这时候实例可以初始化,而数据库忽略SGA_MAX_SIZE的设定。
对大部分系统的性能优化来说,整个SGA应该都在实际内存中。如果做不到,而SGA的一部分使用的虚拟内存,然后数据库系统的整体性能可能迅速下降。原因在于SGA的一部分被操作系统换页(在磁盘上读写)。SGA中分配给所有共享区域的内存数量也对性能有影响。
SGA的尺寸由多个初始化参数指定。下列参数对于SGA尺寸影响很大:
参数
描述
DB_CACHE_SIZE
标准块的缓存尺寸
LOG_BUFFER
重做日志缓存分配的字节
SHARED_POOL_SIZE
专门用于共享SQL和PL/SQL语句的区域字节数
LARGE_POOL_SIZE
大池的尺寸,默认为0
JAVA_POOL_SIZE
Java池大小
自动共享内存管理(Automatic Shared Memory Management)
在以前的数据库版本中,数据库管理员(DBA)通过设置一系列初始化参数(包括SHARED_POOL,DB_CACHE_SIZE,JAVA_POOL_SIZE和LARGE_POOL_SIZE)来手工指定不同的SGA组件尺寸。Oracle 10g数据库包含自动共享内存管理特性,它显著的简化了SGA内存管理。在Oracle 10g数据库中,一个数据库管理员可以使用初始化参数SGA_TARGET参数来指定实例的SGA内存总量,Oracle数据库可以在多个组件中自动分布内存,确保有效使用内存。
当启用了自动SGA内存管理,不同的SGA组件的尺寸是动态变化的,可以适合工作负载的需要而不需要额外的配置。数据库根据需要自动在多个组件之间分布可用内存,允许系统最大化使用所有可用SGA内存。
考虑在SGA可用内存为1GB时手工配置,使用如下初始化参数分布:
SHARED_POOL_SIZE=128M
DB_CACHE_SIZE=896M
如果一个应用试图对共享池分配多于128M的内存,会产生一个错误提示可用共享内存已经耗尽了。在数据库高速缓存中可能还有空闲的内存,但是这些内存不能被共享池使用。你不得不手工重新调整高速缓存(buffer cache)和共享池(shared pool)来解决这个问题。
通过自动SGA管理,你可以简单的设置初始化参数SGA_TARGET为1G。如果应用需要更多的共享池内存,它可以从高速缓存(buffer cache)中获得空闲的内存。
设置一个简单的参数可以大大简化管理员工作。你只需要指定实例可用的SGA内存总量,不用考虑单独组件的大小设置。只要系统事实上没有耗尽内存,就不会产生内存错误。
自动SGA管理可以提高负载性能,而不需要额外的资源和手工的调整。使用SGA手工配置,可能因为内存不足,造成编译的SQL语句从共享池中频繁老化(即清理出共享池)。这会导致频繁硬解析,导致性能降低。当自动SGA管理启用时,一个内部机制会监控负载性能,如果它认为提升共享池尺寸可以降低需要的解析数量,就会提升共享池尺寸。
初始化参数SGA_TARGET
SGA_TARGET初始化参数影响整个SGA尺寸,包括下列组件的内存:
u 固定SGA和其他Oracle数据库实例需要的内部分配
u 日志缓存(log buffer)
u 共享池(shared pool)
u Java池(Java pool)
u 高速缓存(buffer cache)
u 保存池和循环池缓存(keep and recycle buffer caches,如果指定的话)
u 非标准块尺寸的高速缓存(如果指定的话)
u 流池(Streams pool)
SGA_TARGET包含SGA的全部内存是有重大意义的,和以前的发布版本比较,内部和固定SGA加入SGA内存配置参数的总和中。因而SGA_TARGET可以让你精确控制数据库分配给共享内存区域的大小。如果启动时SGA_TARGET设置值大于SGA_MAX_SIZE,然后后者会根据SGA_TARGET调整。
注意:不能动态设置和取消SGA_TARGET参数。只有在实例启动时设置。
自动管理SGA组件
当你设置SGA_TARGET值时,Oracle 10g数据库自动定义大多数通用配置组件的尺寸,包括:
u 共享池(SQL和PL/SQL执行)
u Java池(Java执行区域)
u 大池(大的内存分配,如RMAN备份缓存)
u 高速缓存(buffer cache)
u 流池
你不需要显式的设置这些组件的大小。默认这些组件的相关参数的值都为0。无论何时一个组件需要内存,另一个组件根据内部自动调整机制传输一部分内存给它。内存传输是完全透明的,不需要用户干预。
Oracle数据库实例监控每个自动改变尺寸的组件的性能。实例使用内部视图和统计信息来确定在这些组件之间如何分布内存最优。当负载改变时,内存会重新分布来确保最优性能。为了计算最优的内存分布,数据库使用一种机制同时考虑长期和短期趋势。
手工管理SGA组件
有些SGA组件的尺寸是不能自动调整。如果应用需要的话,管理员需要显式的指定这些组件的大小。这些组件是:
u 缓存保持池和循环池(DB_KEEP_CACHE_SIZE和DB_RECYCLE_CACHE_SIZE控制)
u 非标准块大小的额外高速缓存(参数DB_nK_CACHE_SIZE,n={2,4,8,16,32})
这些组件的大小由管理员定义对应的参数值来确定。这些值当然可以在任何时候通过企业管理器或者ALTER SYSTEM语句在命令行改变。
手工指定大小的组件消耗的内存减少了自动调整的可用内存量。例如,在下面的配置中:
SGA_TARGET = 256M
DB_8K_CACHE_SIZE = 32M
这个实例只有224M(256-32)可以用来在自动调整组件之间分布内存。
自动调整值的持久性
如果你使用服务器参数文件(SPFILE),即使关闭重启,Oracle数据库也会记住自动调整组件的大小。因此,系统不需要在实例重启时再次学习负载的规格参数。它可以从上一个实例的信息开始,并可以从上次关闭的中断继续评估负载。
跟踪组件大小和增加颗粒
数据库管理员使用ALTER SYSTEM语句来修改相关组件的初始化参数值来扩张SGA一个组件的使用。Oracle数据库将新值转换为最近的16MB的整数倍,进而增加和减少颗粒来达到目的值。数据库必须有足够的空闲颗粒才满足需求。只要SGA内存的当前值小于SGA_MAX_SIZE,数据库就可以分配更多的颗粒,直到SGA尺寸达到SGA_MAX_SIZE为止。
SGA中每个组件当前使用的颗粒值可以在视图V$SGAINFO中显示。每个组件大小和上次重定义组件大小的操作时间和类型可以在V$SGA_DYNAMIC_COMPONENTS视图中看到。数据库保存最近400次修改SGA组件的操作。你可以在视图V$SGA_RESIZE_OPS中看到这些缓存的循环。
注意:如果你指定一个组件尺寸不是颗粒大小的倍数,然后Oracle增加指定大小到最近的倍数。例如,如果颗粒大小是4MB,你指定了DB_CACHE_SIZE为10MB,你最终被分配的是12MB。
数据库高速缓存(buffer cache)
数据库高速缓存是SGA的一部分,保存从数据文件读取的数据块的拷贝。所有并发访问实例的用户共享访问数据库高速缓存。
数据库高速缓存和共享SQL缓存逻辑上分为多个集合。组织为多个集合降低了多处理器环境的争用。
数据库高速缓存的组织
高速缓存分为两个列表:写列表和最近最少使用列表(LRU)。写列表保存脏缓存,这部分包含已经修改了但是还没有写入磁盘的数据。LRU列表保存空闲缓存、钉住缓存、还没有移入写列表的脏缓存。空闲缓存不包含任何有用数据,是可用的。钉住缓存是当前访问的缓存。
当Oracle进程访问一个缓存,进程会将缓存移动到LRU列表的最近经常使用端。随着更多的缓存移动到LRU列表的最近经常使用端,脏块顺着LRU列表的最近最少使用端老化。
当Oracle用户进程第一次请求一个特定的数据,它先在数据库高速缓存中查找数据。如果进程发现数据已经在缓存中(cache hit),它可以直接从内存中读取数据。如果进程不能在缓存中找到数据(cache miss),它必须从磁盘上的数据文件拷贝数据块到缓存中,然后才能访问数据。通过Cache hit访问数据比Cache miss访问要快的多。
在读取数据块到缓存之前,进程必须首先找到空闲的缓存。进程搜索LRU列表,从最近经常使用端开始搜索。进程或者找到空闲的缓存,或者达到缓存的阀值限制为止。
如果用户进程在搜索LRU列表找到一个脏缓存,它移动缓存到写列表,然后继续搜索。当进程找到空闲缓存时,它将磁盘上的数据块读取到缓存中,并移动这个缓存到LRU列表的最近经常使用端。
如果一个Oracle用户进程查找达到缓存阀值限制也没有知道空闲缓存,进程停止搜索LRU列表,给DBW0后台进程发信号将某些脏块写入磁盘。
LRU策略和全表扫描
当用户进程执行一个全表扫描,它读取表的块到缓存中,并将它们放到LRU列表的LRU端(而不是MRU端)。这是因为一个全表扫描通常只有少数情况下才需要,所以块应该快速从缓存中移除,留下更多的空间给经常使用的块。
你可以控制基于表扫描的表块的默认行为。在表或聚集创建时使用CACHE子句就可以指定表块在全表扫描期间放置在LRU列表的MRU端。你可以对经常查找的小表或者大的静态历史表指定这种行为来在顺序访问表时减少I/O。
数据库高速缓存的大小
Oracle支持一个数据库中多个块大小。SYSTEM表空间使用的是标准块大小。你可以通过设定初始化参数DB_BLOCK_SIZE来指定标准块大小。合法块大小为2K到32K。
如果需要的话,你可以设置两个额外的缓冲池,通过DB_KEEP_CACHE_SIZE和DB_RECYCLE_CACHE_SIZE来设置保持(KEEP)和循环(RECYCLE)池。这3个参数是相互独立的。
非标准块大小的缓存的尺寸和数量可以通过下列参数指定:
DB_2K_CACHE_SIZE
DB_4K_CACHE_SIZE
DB_8K_CACHE_SIZE
DB_16K_CACHE_SIZE
DB_32K_CACHE_SIZE
每个参数指定了对应块大小的缓存尺寸。
设置块和缓存大小的例子
DB_BLOCK_SIZE=4096
DB_CACHE_SIZE=1024M
DB_2K_CACHE_SIZE=256M
DB_8K_CACHE_SIZE=512M
在前面的例子中,参数DB_BLOCK_SIZE设置了数据库的标准块大小为4K。标准块大小的缓存大小为1024M。另外,2K和8K块的缓存也定义了,分别为256MB和512MB。
注意:DB_nK_CACHE_SIZE参数不能用于标准块大小的缓存大小的设置。如果参数DB_BLOCK_SIZE的值是nK,设置DB_nK_CACHE_SIZE是非法的。标准块的缓存大小总是由DB_CACHE_SIZE的值指定。
缓存有一个限制值,所以不是所有磁盘上的数据都能放到缓存中。当缓存充满时,随后的cache miss会导致Oracle将缓存中存在的脏块写入磁盘,腾出空间来容纳新的数据。(如果一段缓存不脏,那么在新块读入缓存之前不需要将其写入到磁盘)。随后对于已经写入磁盘的任何数据的访问都会导致cache miss。
缓存的大小会影响以cache hit方式访问数据的可能性。如果Cache很大,它更可能包含需要访问的数据。提高Cache的尺寸会提高cache hit访问数据的百分比。
你可以在实例运行时修改buffer cache的大小,而不需要关闭数据库。修改bufer cache大小可以使用ALTER SYSTEM语句。更多的信息,可以参考“控制SGA的内存使用”。
使用固定视图V$BUFFER_POOL来跟踪不同cache组件的大小和任何将要发生的重新定义大小的操作。
多个缓冲池
你可以使用几个缓冲池来定义数据库buffer cache,这些缓冲池可以让数据保存在buffer cache中或者数据块在缓存中只保存一次(使用之后就清除,留给新数据使用)。特定的模式对象(表、聚集、索引和分区)可以分配合适的缓冲池来控制它们的数据库在cache中如何老化:
u KEEP缓冲池:在内存中保持模式对象的数据块
u RECYCLE缓冲池:立即清理不再使用的数据块出内存
u DEFAULT缓冲池:包含没有分配任何缓冲池的模式对象的数据块,和显式分配到DEFAULT缓冲池的模式对象一样处理。
配置KEEP和RECYCLE缓冲池的初始化参数是DB_KEEP_CACHE_SIZE和DB_RECYCLE_CACHE_SIZE。
注意:多缓冲池只对标准块有效,非标准块Cache只有一个DEFAULT池。
重做日志缓存
重做日志缓存是SGA中保存数据库的修改信息的循环缓存。这些信息是重做条目。重做条目包含由INSERT、UPDATE、DELETE、CREATE、ALTER或DROP操作造成的修改的重构或者重做信息。重做条目必要时可以用于数据库恢复。
重做记录由Oracle数据库进程从用户的内存空间拷贝到SGA的重做日志缓冲中。重做记录在缓存中按照顺序保存。后台进程LGWR将重做日志缓存写入到磁盘上的当前活动的重做日志文件中(一组文件)。
初始化参数LOG_BUFFER指定了重做日志缓存的大小(字节)。通常来说,大尺寸可以降低日志文件I/O,特别是长事务或多个事务时。默认值是512K和CPU数目乘以128K两者的最大值。
共享池(Shared Pool)
共享池是SGA中的一部分,包含库缓存、数据字典缓存、并行执行消息的缓存、控制结构。
共享池的大小由初始化参数SHARED_POOL_SIZE来指定。32位平台的默认值为8M,64位平台的默认值为64M。提高这个参数的大小可以提高共享池保留的内存数量。
库缓存
库缓存包括共享SQL区域、私有SQL区域(在使用共享服务器的情况下)、PL/SQL过程和包、诸如锁和库缓存句柄的控制结构。
共享SQL区域对于所有用户都可以访问,所以库缓存包含在SGA的共享池中。
共享SQL区域和私有SQL区域
Oracle中每个SQL语句在共享SQL区域和私有SQL区域中执行。Oracle可以识别两个用户执行的相同的SQL语句,并对于这些用户重用共享SQL区域。但是每个用户必须有语句私用SQL区域的一个拷贝。
共享SQL区域
一个共享SQL区域包含一个给定SQL语句的解析树和执行计划。Oracle通过对多次使用的SQL语句使用同一个共享内存区域来节省内存,这种情况在多个用户同时运行一个应用时经常出现。
Oracle在一个SQL语句被解析后,就会从共享池分配内存将其保存在共享SQL区域中。分配内存的大小依赖于语句的复杂程度。当整个共享池都被分配了,Oracle会使用一个改进的LRU(最近最少使用)算法来从池中释放一些条目,直到可以容纳新语句的共享内存区域为止。如果Oracle释放了一个共享SQL区域,相关SQL语句下次执行时必须重新解析和重新分配另外一块共享SQL区域。
PL/SQL程序单位和共享池
Oracle执行PL/SQL程序单位(过程、函数、包、匿名块、数据库触发器)和处理单独SQL语句方式类似。Oracle分配一个共享区域来保存程序单位的解析、编译格式。Oracle还分配一个私有区域来保存运行程序单位的会话的信息,包括正在执行的SQL的本地、全局和包变量(也可以说是包实例)和缓存。如果多个用户运行同一个程序单位,那么所有用户使用同一个共享区域,而每个用户保存他或者她的私有SQL区域的一个单独拷贝,这里保存着他或她的会话信息。
PL/SQL程序单位里面的单独SQL语句处理起来和前一部分描述的一样。不管它们是否来源于PL/SQL程序单位,这些SQL语句使用一个共享区域来保存它们的解析树,每个语句使用一个私有区域来保存语句所在会话的信息。
数据字典缓存
数据字典是一些包含数据库信息、数据库结构和用户信息的表、视图的集合。Oracle在SQL语句解析时经常访问数据字典。这个访问对于Oracle持续运行是必需的。
数据字典经常访问,所以Oracle在内存中分配了两个区域来专门保存字典数据。一个区域叫做数据字典高速缓存,也叫做行高速缓存(因为它保存了数据行,而不是保存整个块的数据的一个缓存)。另一个内存区域是在库高速缓存中保存数据字典数据的。所有的Oracle用户进程共享这两个高速缓存(cache)来访问数据字典信息。
共享池中内存的释放和重新使用
通常来说,共享池中的任何条目(共享SQL区域或者字典行)都一直保持,除非通过改进的LRU算法清理出去。如果共享池必须为新的条目分配空间时,不再经常使用的内存条目就会被释放。一个改进的LRU算法允许被很多会话使用的共享池条目只要是有用的,就一直保存在内存中,即使创建这个条目的原始进程结束也是如此。因此一个多用户Oracle系统的SQL语句处理和开销是非常小的。
当一个SQL语句提交给Oracle来执行时,Oracle自动执行下列的内存分配步骤:
1、Oracle检查共享池来看共享内存区域是否已经存在相同的语句。如果找到了,共享内存区域就被随后执行的语句实例使用。如果没有这个语句的共享SQL区域,Oracle会在共享池中分配一个共享SQL区域。任一情况下,都会创建对应共享SQL区域的私有SQL区域。
注意:共享内存区域能够从共享池中清除,甚至对应于一个一段时间不再使用的打开的游标对应的共享SQL区域也是如此。如果这个游标随后被调用而需要运行它的语句,Oracle重新解析语句,共享池分配一个新的共享SQL区域。
2、Oracle基于会话分配一个私有SQL区域。私有SQL区域的位置依赖于构成连接的会话的类型。
Oracle还在这些情况下从共享池中清理共享SQL区域:
u 当使用ANALYZE语句来更新或者删除表、聚集、索引的统计信息,所有包含分析的模式对象对应的共享SQl区域会被从共享池中清理出去。清理出去的语句下一次运行时,语句在新的共享SQL区域中分析来反映模式对象的新的统计信息。
u 如果SQL语句引用的模式对象最近被修改过结构,共享SQL区域就是无效的(标识为无效),下次语句执行时必须被重新解析。
u 如果你修改了数据库的全局数据库名字,共享池的所有信息都被清理出去
u 管理员可以手工的清除共享池的所有信息来在不需要关闭当前实例的情况评估性能。ALTER SYSTEM FLUSH SHARED_POOL语句就是用来干这个的。
大池
数据库管理员可以配置一个可选的内存区域(叫做大池)来为下列情况提供大内存分配:
u 共享服务器和Oracle XA接口(多个数据库交互的事务会用到)
u I/O服务器进程
u Oracle备份和恢复操作
通过在大池中为共享服务器、Oracle XA或者并发查询缓存分配内存,Oracle可以使用共享池集中缓存共享SQL,避免收缩共享SQL缓存导致性能瓶颈。
另外,Oracle备份和恢复操作、I/O服务器进程、并发缓存需要分配的缓存可能达几百MB,大池比共享池更适合这样大内存请求。
大池并没有LRU列表。它和共享池的备用区域不同,这个区域和其他共享池中的内存分配一样使用了LRU列表。
Java池
Java池内存是JVM内的所有会话级别的Java代码和数据使用的服务器内存。Java池内存使用方式依赖于Oracle服务器的运行模式。
Java池顾问统计提供了Java使用的库缓存信息,推测Java池如何变化能影响的解析比例。Java池顾问在statistics_level设置为TYPICAL或者更高时内部开启。如果顾问关闭,统计信息复位。
流池
在一个单独数据库中,你可以声明一个流池,流池是从SGA中的一个池中分配一个流内存。要配置流池的话,使用初始化参数STREAMS_POOL_SIZE来指定池的大小(字节数)。如果流池没有定义,那么流第一次使用时会自动创建。
如果设置了SGA_TARGET,那么SGA内存中流池来源于SGA的全局池。如果没有设置SGA_TARGET,然后SGA的流池从其他高速缓存中分配。这个分配只发生在第一次使用流时,分配量是共享池大小的10%。
控制SGA的内存使用
动态SGA提供了对于增加和减少Oracle物理内存使用的更多控制。包括动态buffer cache、共享池和大池,动态SGA允许下列情况:
u SGA可以根据数据库管理员语句增长,上限为操作系统最大内存和SGA_MAX_SIZE的值。
u SGA可以根据数据库管理员语句收缩,下限为Oracle预定义最小值,通常是操作系统限制优先。
u SGA池和buffer cache都可以在运行时根据Oracle管理策略的一些内部机制来增长和收缩。
其他SGA初始化参数
你可以使用多个初始化参数来控制SGA任何使用内存。
物理内存
LOCK_SGA参数将SGA锁定在物理内存中(即SGA只使用物理内存)
SGA开始地址
参数SHARED_MEMORY_ADDRESS和HI_SHARED_MEMORY_ADDRESS指定了SGA运行时的开始地址。这些参数很少使用。在64位平台上,HI_SHARED_MEMORY_ADDRESS指定了64位地址的高32位地址。
扩展Buffer Cache机制
参数USE_INDIRECT_DATA_BUFFERS对32位平台启用扩展bufer cache机制,这样就可以支持多于4G的物理内存。在不支持那么多物理内存的平台上,忽略这个参数。
程序全局区概述(PGA)
程序全局区(PGA)是一个包含服务器进程的数据和控制信息的内存区域。这是Oracle服务进程启动时创建的非共享内存。它是这个服务器专用的内存,只能由Oracle代码代表它读写。一个Oracle实例的每个服务器进程分配的PGA内存总和也叫做实例分配的聚集PGA内存。
PGA的目录
PGA的内存条目针对是否启用了共享服务器而不同。但通常来说,PGA内存可以按照以下分类:
私有SQL区域
私有SQL区域包含绑定信息和运行时内存结构。每个执行SQL语句的会话都有一个私有SQL区域。每个提交相同SQL语句的用户都有他或她自己的私有SQL区域,并且共享同一个共享SQL区域。因而,一个共享SQL区域可以对应于多个私有SQL区域。
一个游标的私有SQL区域分成两个部分,它们的生命周期不同:
u 持久区域,包括诸如绑定信息。在游标关闭时释放
u 运行时区域,只有在执行结束时释放。
Oracle在执行请求的第一步创建运行时区域。对于INSERT、UPDATE、DELETE语句,Oracle在语句运行之后释放运行时区域。对于查询来说,Oracle只有在所有行都获取之后或者查询被取消之后才会释放运行时区域。
私有SQL区域的位置依赖于创建会话的连接类型。如果会话通过专用服务器连接,私有SQL区域位于服务器进程的SGA中。但是,如果会话通过共享服务器连接,私有SQL区域的一部分保存在SGA中。
游标和SQL区域
Oracle预编译程序或者OCI程序的应用开发人员可以显示的打开具体的私有SQL区域的游标或句柄,在程序执行期间像一个命名资源那样使用它们。Oracle隐式执行的一些SQL语句的递归游标也使用共享SQL区域。
私有SQL区域的管理是用户进程的责任。虽然一个用户进程可以分配的私有SQL区域数量总是由初始化参数OPEN_CURSORS限制,但私有SQL区域的分配和释放很大程度上依赖于你使用的应用程序工具。这个参数的默认值为50.
一个私有SQL区域一直存在,除非对应的游标关闭或者语句句柄被释放。Oracle在语句完成时释放了运行时区域,但持久性区域还保持等待状态。应用开发人员需要管理所有的不再使用的打开游标来释放持久性区域和最小化应用程序用户需要的内存数量。
会话内存
会话内存是一个保存会话变量(登陆信息)和其他会话相关信息的内存。对于共享服务器,会话内存是共享的,而不是私有的。
SQL工作区域
对于复杂的查询(例如决策支持查询),运行时区域的一大部分用于内存密集型操作符分配的工作区域,例如:
u 排序操作符(order by,group-by,rollup,window,function)
u 哈希关联
u 位图合并
u 位图创建
例如,一个排序操作符使用一个工作区域(有时叫做排序区域)来执行一系列行在内存中的排序。类似的,哈希关联操作符使用一个工作区域(也叫做Hash区域)来从它的左输入来构建hash表。如果这两个操作符操作的数据量不能都放在工作区域中,然后输入数据会分成更小的一些片。这导致某些数据片在内存中处理,而剩下的部分放在临时磁盘存储上,等待后续执行。虽然位图操作符在它们工作区太小时不会溢出到磁盘,但是它们的复杂程度和工作区域的大小成反比。因而,这些操作符在大工作区域中运行起来更快。
工作区域的大小可以控制和调整。通常,大数据库区域可以提高特定的大量消耗内存的操作符的性能。理想情况下,工作区大小应该足够容纳输入数据和相关SQL操作符分配的辅助存储结构。如果做不到,会增加反应时间,因为输入数据的一部分必须溢出到临时磁盘存储上。在极端情况下,如果工作区域相对输入数据来说太小,数据片必须多次装入。这会出人意料的增加操作符的反应时间。
专用服务器模式下的PGA内存管理
你可以整体上自动管理SQL工作区域的大小。数据库管理员可以通过设置初始化参数PGA_AGGREGATE_TARGET来简化设置PGA内存的总体尺寸的工作。指定值(例如 2G)是Oracle实例的总体值,Oracle视图确保所有服务器进程分配的PGA内存总量不能超过这个值。
注意:在早期版本中,数据库管理员通过下列参数控制SQL工作区域的最大值:SQL_AREA_SIZE,HASH_AREA_SIZE,BITMAP_MERGE_AREA_SIZE和CREATE_BITMAP_AREA_SIZE。设置这些参数是非常困难的,因为最优的最大的工作区域大小要在数据输入大小和系统中活动的全部工作区域之间选择。这两个因素在工作区域之间和不同的时间段都会不同。因而,不同的*_AREA_SIZE参数在最好的情况下也很难调整。
通过PGA_AGGREGATE_TARGET,所有专用会话的工作区域的大小是自动调整的,所有的*_AREA_SIZE都被忽略。在任何给定的时间内,实例中活动的工作区域的总体PGA内存数量自动从参数PGA_AGGREGATE_TARGET中分配。这个数量是指PGA_AGGREGATE_TARGET减去系统其他组件分配的PGA内存(例如,会话分配的PGA内存)。剩下的PGA内存为每个活动工作区域根据他们需要的内存分配给它们。
注意:初始化参数WORKAREA_SIZE_POLICY是一个会话和系统级别的参数,只能有两个值MANUAL和AUTO。默认是AUTO。数据库管理员可以设置PGA_AGGREGATE_TARGET,然后从自动内存管理模式转回到手工内存管理模式。
有些固定视图和列可以提供PGA内存的使用统计信息。在PGA_AGGEGATE_TARGET被设置时,可以启动大部分统计信息。
u 工作区域内存的分配和使用统计信息可以在下列动态性能视图中显示:
V$SYSSTAT
V$SESSTAT
V$PGASTAT
V$SQL_WORKAREA
V$SQL_WORKAREA_ACTIVE
u 视图V$PROCESS的下面三列报告了一个Oracle进程分配和使用的PGA内存:
PGA_USED_MEM
PGA_ALLOCATED_MEM
PGA_MAX_MEM
注意:自动PGA内存管理模式在共享和专用服务器下都可以分配工作区域。
专用和共享服务器
内存分配在一些细节上依赖于是否使用了专用或者共享服务器架构。表8-1显示了其中的区别。
表8-1 共享和专用服务器中内存分配的不同
内存区域
专用服务器
共享服务器
会话内存的种类
私有
共享
持久区域的位置
PGA
SGA
SELECT语句的运行时区域的部分位置
PGA
PGA
DML/DDL语句的运行时区域的位置
PGA
PGA
软件代码区域
软件代码区域是保存正在运行或可以运行的代码的内存区域。Oracle代码保存在软件代码区域,它和用户程序的位置不同,是更专用或更加保护的位置。
软件区域大小通常是固定的,只有在软件升级或者重新安装时改变。这些区域需要的尺寸和操作系统有关。
软件区域是只读的,可以共享使用,也可以不共享使用。尽可能的情况下,Oracle代码是共享的,所有的Oracle用户都可以访问,这样内存中就不用保存多份拷贝了。这样可以节省物理内存和提升总体性能。
用户程序也可以共享,也可以不共享。某些Oracle工具和公共程序(如Oracle窗体和SQL *PLUS)可以共享,但某些不能。Oracle多个实例如果运行在一台机器上可以使用相同的Oracle代码区域。
注意:共享软件安装的选项不是在所有的操作系统上都可用(例如,在PC的windows系统上)。
查看你的Oracle操作系统规格文档来查找更多的信息。