《Oracle编程艺术》学习笔记(10)-SGA,PGA,UGA和memory_target

 Oracle有3个主要的内存结构:
系统全局区(System Global Area,SGA)是一个很大的共享内存段,几乎所有Oracle进程都要访问这个区中的某一点。
进程全局区(Process Global Area,PGA)是一个进程或线程专用的内存,其他进程/线程不能访问。
用户全局区(User Global Area,UGA):这个内存区与特定的会话相关联,保存会话的状态。如果使用共享服务器,UGA 就在SGA 中分配;如果使用专用服务器,UGA就会在PGA(即进程内存区)中。

Oracle中有2种办法管理内存。一种是自动管理,一种是手动管理。
自动管理有2个层次,
第一个层次,需要设置2个参数(sga_target和pga_aggregate_target),以确定SGA和PGA的大小;
第二个层次(11g之后),只需要设置memory_target这一个参数,Oracle自动确定所有内存区大小。

PGA

PGA内存管理受数据库初始化参数WORKAREA_SIZE_POLICY的控制,而且可以在会话级修改。在Oracle9i Release 2 及以上版本中,这个初始化参数默认为AUTO,表示自动PGA内存管理。

如果参数WORKAREA_SIZE_POLICY是MANUAL,则启动手动PGA内存管理,以下参数对PGA大小的影响最大:
·SORT_AREA_SIZE:在信息换出到磁盘之前,用于对信息排序的RAM总量。
·SORT_AREA_RETAINED_SIZE:排序完成后用于保存已排序数据的内存总量。这部分内存一般从UGA中分配。
也就是说,如果SORT_AREA_SIZE是512 KB,SORT_AREA_RETAINED_SIZE是256 KB,那么服务器进程最初处理查询时会用512 KB的内存对数据排序。等到排序完成时,排序区会“收缩”为256 KB,这256 KB内存中放不下的已排序数据会写出到临时表空间中。
·HASH_AREA_SIZE:服务器进程在内存中存储散列表所用的内存量。散列联结时会使用这些散列表结构,通常把一个大集合与另一个集合联结时就会用到这些结构。两个集合中较小的一个会散列到内存中,散列区中放不下的部分都会通过联结键存储在临时表空间中。

如果WORKAREA_SIZE_POLICY设置为AUTO,PGA_AGGREGATE_TARGET有一个非0值,就会使用自动PGA内存管理。

对于OLTP应用,倾向于使用自动PGA 内存管理。手动内存管理则适用于大型批处理作业(它们在特殊的时段运行,此时它们是数据库中惟一的活动)。


SGA
可以通过
select pool, name, bytes from v$sgastat order by pool, name;
语句了解SGA的详细状况。
主要的SGA组件有:
1)固定SGA(fixed SGA)
无法控制固定SGA的大小,不过固定SGA通常都很小。可以把这个区想成是SGA中的“自启”区,Oracle在内部要使用这个区来找到SGA 的其他区。

2)重做缓冲区(redo buffer)
在线重做日志在写至磁盘之前,要在重做缓冲区中临时缓存这些数据。
由于内存到内存的传输比内存到磁盘的传输快得多,因此使用重做日志缓冲区可以加快数据库的操作。

3)块缓冲区缓存(block buffer cache)
Oracle从磁盘读取数据库块之后,将数据库块写至磁盘之前,就会把这些数据库块存储在块缓冲区缓存(block buffer cache)中。这是SGA中一个很重要的区。
SGA中各个段的已缓存块放在3个位置上:
·默认池(default pool):所有段块一般都在这个池中缓存。
·保持池(keep pool):按惯例,访问相当频繁的段会放在这个候选的缓冲区池中。
·回收池(recycle pool):按惯例,访问很随机的大段可以放在这个候选的缓冲区池中。
实际上,这3个池会以大体相同的方式管理块;将块老化或缓存的算法并没有根本的差异。这样做的目标是让DBA能把段聚集到“热”区(hot)、“温”区(warm)和“不适合缓存”区(do not care to cache)。
理论上讲,默认池中的对象应该足够热(也就是说,用得足够多),可以保证一直呆在缓存中。缓存会把它们一直留在内存中,因为它们是非常热门的块。可能还有一些段相当热门,但是并不太热;这些块就作为温块。为了保持这些温段的块得到缓存,可以将这些段分配到保持池,力图让温块在缓冲区缓存中停留得更久。将“不适合缓存”段分配到回收池,让回收池相当小,以便块能快速地进入缓存和离开缓存(减少管理的开销)。
默认池、保持池和回收池只缓存具有默认大小的块((最初创建数据库时使用的块大小)。
如果要在数据库中使用非默认的块大小,需要配置一个缓冲区池来保存这些块。
例如,当前数据库默认块大小为8K,如如果执行
create tablespace ts_16k datafile 'c:\ts_16k.dbf' size 2m blocksize 16k;
试图创建1个16K的块大小的tablespace,会得到1个"ORA-29339: 表空间块大小 16384 与配置的块大小不匹配"的错误。说明需要建立1个16K块大小的块缓冲区。
可以设置DB_16K_CACHE_SIZE 参数,并重启数据库。
也可以缩小另外的某个SGA组件,从而在现有的SGA中腾出空间来建立一个16 KB的缓存。
或者,如果SGA_MAX_SIZE 参数大于当前的SGA 大小,可以直接分配一个16 KB的缓存。
之后就可以成功建立这个16K块大小的tablespace。

4)共享池(shared pool)
共享池就是Oracle缓存一些“程序”数据的地方,系统参数,数据字典缓存,已解析的查询计划等也存储在这里。
共享池中的内存根据LRU(最近最少使用)的原则来管理,类似于块缓冲区缓存。

Oracle 将已解析、已编译的SQL 连同其他内容存储在共享池(shared pool)中。
这就要求开发人员在大多数情况下都会使用绑定变量(bind variable)。例如:
select * from emp where empno = :empno;
这个查询只编译一次,随后会把查询计划存储在一个共享池(库缓存)中,以便以后获取和重用这个查询计划。
如果你确实想让Oracle缓慢地运行,甚至几近停顿,只要根本不使用绑定变量就可以办到:
select * from emp where empno = 123;
如果在查询中使用直接量(常量),那么每个查询都将是一个全新的查询,在数据库看来以前从未见过,必须对查询进行解析、限定(命名解析)、安全性检查、优化等。简单地讲,就是你执行的每条不同的语句都要在执行时进行编译。
与重用已解析的查询计划(称为软解析,soft parse)相比,解析包含有硬编码变量的语句(称为硬解析,hard parse)需要的时间更长,而且要消耗更多的资源。
更重要的因素是库缓存所用的闩定(latching)机制。硬解析一个查询时,数据库会更长时间地占用一种低级串行化设备,这称为闩(latch),这些闩能保护Oracle共享内存中的数据结构不会同时被两个进程修改(否则,Oracle 最 后会得到遭到破坏的数据结构),而且如果有人正在修改数据结构,则不允许另外的人再来读取。对这些数据结构加闩的时间越长、越频繁,排队等待闩的进程就越多,等待队列也越长。你可能开始独占珍贵的资源。数据库中只要有一个应用表现不佳,就会严重地影响所有其他应用的性能。如果只一个小应用没有使用绑定变量,那么即使其他应用原本设计得很好,能适当地将已解析的SQL 放在共享池中以备重用,但因为这个小应用的存在,过一段时间就会从共享池中删除已存储的SQL。这就使得这些设计得当的应用也必须再次硬解析SQL。
不使用绑定变量是导致性能问题的一个主要原因,也是阻碍可扩缩性的一个重要因素。

不使用绑定变量的另外一个影响,就是安全性,容易受到“SQL注入”攻击。

Oracle 8.1.6 增加了一个新参数CURSOR_SHARING=FORCE。如果你愿意,这个特性会实现一个自动绑定器(auto-binder)。如果有一个查询编写为SELECT * FROM EMPWHERE EMPNO = 1234,自动绑定器会悄无声息地把它改写成SELECT * FROM EMP WHERE EMPNO = :x。这确实能动态地大大减少硬解析数,并减少前面讨论的库闩等待时间——但是它可能有一些副作用。从长远来看,要尽可能地使用绑定变量,而在需要时才使用常量,这才是正确的做法。

5)大池(large pool)
大池用于大块内存的分配,共享池不会处理这么大的内存块。
共享池根据LRU来管理内存,这对于缓存和重用数据很合适。大块内存分配则是得到一块内存后加以使用,然后就到此为止,没有必要缓存这个内存。
大池中分配的内存在堆上管理,与C语言通过malloc()和free()管理内存很相似。一旦“释放”了一块内存,它就能由其他进程使用。在共享池中,实际上没有释放内存块的概念。只是分配内存,然后使用,再停止使用而已。过一段时间,如果需要重用那个内存,Oracle会让你的内存块老化。

大池专门用于以下情况:
·共享服务器连接,用于在SGA 中分配UGA 区。
·语句的并行执行,允许分配进程间的消息缓冲区,这些缓冲区用于协调并行查询服务器。
·备份,在某些情况下用于RMAN磁盘I/O 缓冲区。

6)Java池(java pool)
用于支持在数据库中运行Java。

7)流池(stream pool)
用于支持流(一个数据库共享/复制工具)。

对 SGA 整体大小影响最大的参数如下:
·JAVA_POOL_SIZE:控制Java 池的大小。
·SHARED_POOL_SIZE:在某种程度上控制共享池的大小。
·LARGE_POOL_SIZE:控制大池的大小。
·DB_*_CACHE_SIZE:控制各个可用的缓冲区缓存的大小。
·LOG_BUFFER:在某种程度上控制重做缓冲区的大小。
·SGA_TARGET:Oracle 10g及以上版本中用于自动SGA内存管理。
·SGA_MAX_SIZE:用于控制数据库启动并运行时SGA可以达到的最大大小。
可以通过查询v$sgainfo视图来查看SGA各个组件大小,以及是否可以调整(RESIZEABLE)。

如果采用手动SGA内存管理,需要设置上述各个参数;
如果采用自动SGA内存管理,只需把SGA_TARGET 参数设置为所需的SGA大小,数据库实例会根据工作负载条件在运行时分配和撤销(释放)各个SGA 组件。

关闭数据库时,数据库会把各个SGA组件大小通过一些首部带下划线参数(__DB_CACHE_SIZE、__JAVA_POOL_SIZE、__LARGE_POOL_SIZE 和__SHARED_POOL_SIZE等)记录到存储参数文件(SPFILE)中,并在启动时再使用这些值来设置各个区的默认大小。
另外,如果知道上述4个区中某个区的最小值,那么除了设置SGA_TARGET 外,还可以设置这个参数。实例会使用你的设置作为下界(即这个区可能的最小大小)。

memory_target
11g之后,Oracle提供了自动内存管理,只需要设置memory_target这一个参数,Oracle自动确定所有内存区大小。这种情况下,SGA_TARGET和PGA_AGGREGATE_TARGET这2个参数就被用来设定最小值。
Oracle会把SGA和PGA的最优设置存储到spfile的__sga_target和__pga_aggregate_target这2个参数中。

可以在运行时修改memory_target而不需要重启数据库。
alter system set memory_target=512M;
另外有个参数memory_max_target,指定了memory_target的最大值。如果要修改memory_max_target,必须用scope=spfile参数并重启数据库后生效。

不论是使用自动内存管理还是手动内存管理,各个池的内存以一种称为颗粒(granule)的单位来分配。
通过查询V$SGA_DYNAMIC_COMPONENTS,可以查看各个池所用的颗粒大小。例如:
select component, granule_size from v$sga_dynamic_components;

相关视图
1) v$sga 返回的值和调用startup启动数据库时显示的数据一致。
2) v$sgainfo 可以查到上面所说的记录在spfile中的带下划线的参数值。
3) v$sga_dynamic_components 针对SGA动态内存区大小调整的操作。
4) v$sga_dynamic_free_memory 这个视图只有一个字段就是用来表示SGA当前可用的空闲区域。
5) v$sgastat 可以了解SGA的详细状况。
6) 察看__sga_target和__pga_aggregate_target这2个参数。
select a.ksppinm name,b.ksppstvl value
from x$ksppi a,x$ksppcv b
where a.indx=b.indx
and (a.ksppinm like '%sga_target%'
or a.ksppinm like '%pga_aggregate_target%');

你可能感兴趣的:(数据结构,oracle,编程,数据库,存储,Components)