数据库结构(五).内存结构
Oracle 的内存可以分为:系统全局区(SGA)、程序全局区(PGA)、用户全局区(UGA),其主要用来储存:
1 、程序代码
2 、活动和非活动的session信息
3 、程序执行过程中的信息(例如Cursor)
4 、与 Oracle 进程共享和通信的信息(例如锁)
5 、被缓存到内存的信息
一、系统全局区(SGA)
SGA 是一组为系统分配的共享内存结构,可以包含多个数据库实例的数据或控制信息。当实例启动时, SGA 即被自动分配,实例关闭时被自动回收。
SGA 按其作用的不同,可以分为:数据缓冲区、日志缓冲区、共享池、大池、 Java 池、流池等。
查看 SGA 的大小可以使用 :
SQL> select * from v$sga;
NAME VALUE
-------------------- ----------
Fixed Size 453492
Variable Size 109051904
Database Buffers 25165824
Redo Buffers 667648
1、数据缓冲区(Database Buffer Cache)
用户第一次执行查询或修改数据操作时,服务器进程将数据从数据文件中读取出来,并装入到数据缓冲区中,这样操作即在内存中完成,用户下一次访问相同数据时, Oracle 可以直接将数据缓冲区中的数据返回给用户,大大提高相应速度。
数据缓冲区由许多相同大小的缓存块组成,其大小与数据块相同,从其是否被利用角度可分为三类:
(1) 脏缓存块:保存了已经被修改过的数据,这些数据需等待 DBWR 要重新被写入数据文件中;
(2) 空闲缓存块:不包含任何数据,等待被写入;
(3) 命中缓存块:用户正在访问的缓存块,这些缓存块将被保留在数据缓冲区中。
Oracle 通过最近最少使用列表(LRU)和写入列表(DIRTY)来管理数据缓冲区中的缓存块。
(1) LRU :包含所有三类缓存块,使用 LRU 算法将缓冲区中最近一段时间内访问次数最少的缓存块移除缓冲区。
(2) DIRTY :包含了已经被修改并需要写入数据文件的缓存块
数据缓冲区的工作机制:
(1) 用户提交访问申请, Oracle 在数据缓冲区中查找,若该数据块位于数据缓冲区中,则直接返回给用户,称之为 “ 缓存命中 ”
(2) 若数据缓冲区中查找不到所需数据块,则先从数据文件提取到缓存中,再从缓存读取并返回给用户,称之为 “ 缓存失败 ”
(3) 当 “ 缓存失败 ” 时,先找到空闲缓存块,若没有空闲块,则将 LRU 列表中的脏缓存块移入 DIRTY 列表
(4) 当 DIRTY 列表到达一定长度时,由 DBWR 将脏数据块的数据写入到磁盘文件,重新刷新数据缓冲区
8i以前的版本,数据缓存的大小由DB_BLOCK_BUFFER(数据缓存区缓存块数量)和DB_BLOCK_SIZE(数据块大小)两者的乘积决定,而在9i以后,直接使用DB_CACHE_SIZE指定。
2、日志缓冲区(Redo Log Buffer)
日志缓冲区用于存储数据库的修改信息。当日志缓冲区的日志信息达到一定数量时,由 LGWR 进程将日志写入到日志文件组。
日志缓冲区是一个直接从顶端向底端写入数据的循环缓冲区,当写到最底端时,再返回到缓冲区的起始点循环写入。
日志缓冲区大小由 LOG_BUFFER 参数指定,并可以在运行的过程中中进行动态修改。日志缓冲区对数据库性能的影响较小,当然设置较大的日志缓冲区可以减少日志文件的 I/O 次数,提高数据库性能。
3、共享池(Shared Pool)
共享池分为:库缓冲区、数据字典缓冲区、用户全局区 三部分。共享池大小由 SHARED_POOL_SIZE 参数设定。
(1) 库缓冲区:缓存 SQL 语句的分析码、执行计划
(2) 数据字典缓冲区:包含从数据字典中得到的表、列定义和权限
(3) 用户全局区:包含了用户的session信息
当一条SQL语句提交时,Oracle首先从共享池的缓冲区内搜索,查看是否有相同SQL被解析并执行,若存在则不必再次解析。
4、大池(Large Pool)
大池是数据库管理员能够配置的可选内存空间,可用于不同类型的内存存储。
Oracle 的某些操作可能需要内存中使用大量的缓存,例如:
1、数据库的备份或恢复操作
2、执行具有大量排序操作的 SQL 语句
3、执行并行化的数据库操作
若没有创建大池,这些操作需要的缓存空间都将在共享池或PGA中分配,大量的占用会影响到共享池和PGA的使用效率。大池的大小通过 LARGE_POOL_SIZE 设定。
注:在共享服务器操作模式下,服务器进程会将session信息存储在大池中,而非共享池。session结束后大池即释放内存。
5、Java池(Java Pool)
Oracle提供了对Java语言的支持,所以提供Java池。 Java池主要用于对Java语言提供语法分析区。
Java 池的大小由参数 JAVA_POOL_SIZE 设定。
6、流池(Stream Pool)
这是Oracle Stream专用的内存池,Oracle Stream是数据库中的一个数据共享工具。
该值由STREAMS_POOL_SIZE指定大小。若未配置该内存区,则当使用到 Stream功能时 ,Oracle会分配共享池中至多10%的空间作为Stream内存。
二、程序全局区(PGA)
PGA是包含单独用户或服务器数据和控制文件的内存区域。PGA由用户连接到数据库时创建,进行自动分配,且是非共享的,只有服务进程本身才能访问它自己的PGA区。
每一个服务进程都有自己的PGA区,PGA的内容与结构和数据库的操作模式(专用/共享服务器)有关。
PGA 按照oracle官方文档解释,叫做程序全局区(Program Global Area),但也有些资料上说还可以理解为进程全局区(Process Global Area)。这两者没有本质的区别,它首先是一个内存区域,其次,该区域中包含了与某个特定服务器进程相关的数据和控制信息。每个进程都具有自己私有的PGA区,这也就意味着,这块区域只能被其所属的进程进入,而不能被其他进程访问,所以在PGA中不需要latch这样的内存结构来保护其中的信息。笼统的来说,PGA里包含了当前进程所使用的有关操作系统资源的信息(比如打开的文件句柄等)以及一些与当前进程相关的一些私有的状态信息。
每个PGA区都包含两部分:
(1) 固定PGA部分(Fixed PGA):这部分包含一些小的固定尺寸的变量,以及指向变化PGA部分的指针。
(2) 变化PGA部分(Variable PGA):这部分是按照堆(Heap)来进行组织的,所以这部分也叫做PGA堆。可以从X$KSMPP视图中看到有关PGA堆的分布信息。PGA堆中所包含的内存结构包括:
有关一些固定表的永久性内存。
如果session使用的是专用连接方式(dedicated server),则还含有用户全局区(UGA-User Global Area)子堆。如果session使用的是共享连接方式(shared server),则UGA位于SGA中。
调用全局区(CGA-Call Global Area)子堆。
三、用户全局区(Sort Area)
UGA是包含与某个特定session相关信息的内存区域,比如session的登录信息以及session私有的SQL区域等。
每个UGA也包含两个部分:
(1) 固定UGA部分(Fixed UGA):这部分包含一些小的固定尺寸的变量,以及指向变化UGA部分的指针。
(2) 变化UGA部分(Variable UGA):这部分也是按照堆来进行组织的,可以从X$KSMUP视图中看到有关UGA堆的分布情况。
UGA堆的分布与OPEN_CURSORS、OPEN_LINKS等参数有关系。所谓的游标(cursor)就是放在这里的。
UGA堆中所包含的内存结构包括:
(1) 私有SQL区域(Private SQL Area):这部分区域包含绑定变量信息以及运行时的内存结构等数据。每一个发出SQL语句的session都有自己的私有SQL区域。
这部分区域又可分成两部分:
(i) 永久内存区域:这里存放了相同SQL语句多次执行时都需要的一些游标信息,比如绑定变量信息、数据类型转换信息等。这部分内存只有在游标被关闭时才会被释放。
(ii)运行时区域:这里存放了当SQL语句运行时所使用的一些信息。这部分区域的大小尺寸依赖于所要执行的SQL语句的类型(sort或hash-join等)和复杂度以及所要处理的数据行的行数以及行的大小。在处理SQL语句时的第一步就是要创建运行时区域,对于DML(INSERT、UPDATE、DELETE)语句来说,SQL语句执行完毕就释放该区域;而对于查询语句(SELECT)来说,则是在所有数据行都被获取并传递给用户以后被释放,或者该查询被取消以后也会被释放。
(2) Session相关的信息。这部分信息包括:
1.正在使用的包(package)的状态信息。
2.使用alter session这样的命令所启用的跟踪信息、或者所修改的session级别的优化器参数(optimizer_mode)、排序参(sort_area_size等)、修改的NLS参数等。
3.所打开的dblinks。
4.可使用的角色(roles)等。
从上面可以很明显的看出,我们最需要关注的就是私有SQL区域中的运行时区域了。实际上,从9i以后,对这部分区域有了一个新的名称:SQL工作区域(SQL Work Area)。SQL工作区域的大小依赖于所要处理的SQL语句的复杂程度而定。如果SQL语句包含诸如group by、Hash-join等这样的操作,则会需要很大的SQL工作区域。实际上,我们调整PGA也就是调整这块区域。后面还会说到这部分内容。
而UGA所处的位置完全由session连接的方式决定:
如果session是通过共享服务器(shared server)方式连到数据库的,则毫无疑问,UGA必须能够被所有进程访问,所以这个时候UGA是从SGA中进行分配的。进一步说,如果SGA中设置了large pool,则UGA从large pool里进行分配;否则,如果没有设置large pool,则UGA只能从shared pool里进行分配了。
如果session是通过专用服务器(dedicated server)方式连到数据库的,则UGA是从进程的PGA中进行分配的。
附一: SGA 各部分大小解析 (转载)
*********************************************************************************
SGA中的The fixed area包含了数千个原子变量,以及如latches和指向SGA中其它区域的pointers(指针)等小的数据结构.通过对fixed table内表X$KSMFSV查询(如下)可以获得这些变量的名字,变量类型,大小和在内存中的地址.
SQL> select ksmfsnam, ksmfstyp, ksmfssiz, ksmfsadr from x$ksmfsv;
这些SGA变量的名字是隐藏的而且几乎完全不需要去知道.但是我们可以通过结合fixed table内表X$KSMMEM获得这些变量的值或者检查它们所指向的数据结构.
SQL>select a.ksmmmval from x$ksmmem a where addr=(select addr from x$ksmfsv where ksmfsnam= ’ kcrfal_ ’ );
SGA中的fixed area的每个组成部分的大小是固定的.也就是说它们是不依靠于其它的初始化参数的设置来进行调整的.fixed area中的所以组成部分的大小相加就是fixed area的大小.
The variable area:
SGA 中的the variable area是由large pool和shared pool组成的.large pool的内存大小是动态分配的,而shared pool的内存大小即包含了动态管理的内存又包含了永久性的(已经分配的)内存.实际上,初始化参数shared_pool_size的大小设置是指定shared pool中动态分配的那部分内存的一个大概的SIZES而不是整个shared pool的SIZES
Shared pool 中永久性的内存包含各种数据结构如 :the buffer headers, processes, sessions, transaction arrays, the enqueue resources , locks, the online rollback segment arrays, various arrays for recording statistics. 其中大部分的SIZE是依靠初始参数的设置来确定的. 这些初始参数只能在实例被关闭的状态下才能够进行修改 . 所以这里说的永久性是针对实例打开状态下的生存期而言. 简单的一个例子PROCESSES参数. 在这个 process arrays 中的 slots 用完之后 , 如果有其它的 process 想再申请一个 process 则会失败 , 因为它们在内存中的大小是在实例启动时预分配的. 不能动态修改之 .
针对很多永久性的 arrays, 有很多的 X$ 表都把这些元素做一个记录而成员结构则作为字段 .V$ 视图的数据就是从这些 X$ 表获得 . 如 V$PROCESS 是基于 X$KSUPR 内表的 .V$PROCESS 视图不包含 X$KSUPR 的全部字段 . X$KSUPR也没有覆盖SGA进程结构的所有成员.
The variable area的在SGA中的SIZES就等于LARGE_POOL_SIZE,SHARED_POOL_SIZE和永久性的内存arrays的SIZE三者相加. 永久性的内存arrays的总的SIZE可以通过初始参数的设置来计算得到.然而,你需要知道从参数获得这些array sizes的方程式,每个array元素大小的字节数,还有array头信息的sizes.这些跟Oracle的版本号和OS有关.实际使用中,我们是不必要计算这个永久性的内存arrays的SIZE的.如果想知道,一个方法就是在STARTUP NOMOUNT数据库时记下the variable area.然后减去参数中LARGE_POOL_SIZE和SHARED_POOL_SIZE的大小就可以.
The database block area:
这个区域是数据库块的拷贝.在Oracle 8i中,buffer数由DB_BLOCK_BUFFERS指定.每个buffer的大小由DB_BLOCK_SIZE指定.所以这个区域的大小是两者相乘.在Oracle 9i中,这个区域的大小是DB_CACHE_SIZE指定.这个区不包含它们自己的控制结构,只包含database block copies data.每个buffer的header信息存在于SGA的the variable area中.还有latches信息也放在SGA的the variable area中.在设置DB_BLOCK_BUFFERS时每4个BUFFERS会影响the variable area的1K的SIZE.关于这一点.可以通过测试(针对8i而言).
The log buffer:
这个区域的SIZE是由参数LOG_BUFFER指定的.如果OS支持内存保护,log buffer将会被两个保护页面包围起来以免被一些ORACLE的错误进程损坏log buffer.在SGA中,跟其它的如variable area和database block area相比,log buffer是非常小的.log buffer分成内部的buffer blocks,而这些block各有8个字节的头部信息存在于variable area中.
The instance lock database:
在OPS/RAC配置中,instance locks用来控制由所有instances共享的资源以串行的方式被进入并使用.SGA中的这个区域所维护的是本地实例所要使用的数据库资源,所有实例和进程都会用到的数据库资源,还有所有实例和进程当前需要的或者已经拥有的锁(LOCKS).这三个arrays的SIZE分别由参数LM_RESS,LM_PROCS,LM_LOCKS参数指定.(这三个参数是RAC的参数,在单实例中用SHOW PARAMETER是查看不到的). The instance lock database还包含了message buffers和其它的structure.但是其SIZE是非常小的.
这个区域的SIZE是没办法在实例启动的时候看到的.这是Oracle Internals.可以用ORADEBUG工具查看.SQL>ORADEBUG IPC.至于ORADEBUG工具就不做介绍.用这个工具做操作时需要经过Oracle Support同意.
可以用以下的两种方式DUMP SGA:
SQL>ALTER SESSION SET EVENTS 'immediate trace name global_area level 2';
或者
SQL>ORADEBUG DUMP GLOBAL_AREA 2;
*********************************************************************************
附二、PGA 管理(转载)
*********************************************************************************
上文是一篇对于PGA的详细介绍,如需仔细了解该部分内容,则可查阅