关于oracle内存管理这一章,还是非常重要滴,不过嫩说白了就三个东西,PGA,UGA,SGA...
先看看PGA:http://blog.csdn.net/changyanmanman/article/details/6856656
再看看SGA:http://blog.csdn.net/changyanmanman/article/details/6875402
pga不多说啦,现在一般是自动管理的,主要再看看sga吧:在命令行里输入show sga,会出现如下几个参数:
fixed size:也叫fixes_sga固定的sga,包括了一些数据库与实例的控制信息、状态信息、字典信息等,这块区域打数据库启动的时候就在sga中,而且永远不会改变。
variable size:包含了share pool,large pool,java pool,stream pool,游标区和其他结构。
database buffers:在v$sgastat视图中叫buffer_catch。有时候也叫data buffer,说白了就是数据库缓冲区,
redo buffers:在v$sgastat视图中叫 log_buffer.为日志写进程提供的一个缓冲区,因为在一般的OLTP系统中提交很频繁,所以一般不大。其大小有log_buffer参数控制其大小取512k和 (128*cpu个数)k 较大者。
在v$sgastat视图中还有一个kqr l po 之类的名字,看看这一篇介绍吧:http://blog.csdn.net/changyanmanman/article/details/7256267
data buffer catch:里面有三个池,在8i以前只有一个默认池,但是以后的版本增加了保持池和回收池。
默认池(由db_catch_size参数决定其大小):一直就有的那个,所有的段块一般都在这个池中,访问最频繁的池。
保持池(db_keep_catch_size):访问相对比较频繁的段块就会被放在这里面,这样就防止了放在默认池中出现老化的情况。
回收池(db_recycle_catch_size):访问很随即,很少的大段一般放在这里,随时可能刷新输出到磁盘,也有可能随时调入进来,这样效率就相对于默认池和保持池的低一点。一般这个池很小,可以让块更快的进出,方便管理。
这样会增加DBA 所要执行的管理工作,因为要考虑3 个缓存,要确定它们的大小,还要为这些缓存分配对象。还要记住,这些池之间没有共享,所以,如果保持池有大量未用的空间,即使默认池或回收池空间不够用了, 保持池也不会把未用空间交出来。总之,这些池一般被视为一种非常精细的低级调优设备,只有所有其他调优手段大多用过之后才应考虑使用(如果可以重写查询, 将I/O 减少为原来的1/10,而不是建立多个缓冲区池,我肯定会选择前者!)。
从Oracle9i 开始,除了默认池、保持池和回收池外,DBA 还要考虑第4 种可选的缓存:db_Nk_caches。增加这些缓存是为了支持数据库中多种不同的块大小。在Oracle9i 之前,数据库中只有一种块大小(一般是2 KB、4 KB、8 KB、16 KB 或32 KB)。从Oracle9i 开始,数据库可以有一个默认的块大小,也就是默认池、保持池或回收池中存储的块的大小,还可以有最多4 种非默认的块大小,与原来默认池中的块一样,这些缓冲区缓存中的块会以同样的方式管理,没有针对不同的池采用任何特殊的算法。
data buffer catch 中的块管理:
在各个池中的管理算法是一样的,我们就以一个默认池(可能有多个默认池)为例,讲述oracle如何管理数据块缓存中的数据块,额,这些块的管理实际上就是位置上的管理,在每个池中都会有两个重要的列表来管理这些块,其中一个列表就是 脏块列表,其中的块在那排着队等待着DBWn 进程将其依次写入磁盘。另一个列表是一个接触计数的表,oracle给每个块加一个接触计数,如果访问这个块的次数多,大约3秒钟这个计数就会加1,但是过一会oracle会自动给你冷却这个块,把这个数再往下减。。块可以在这两种列表中逻辑的移动,记住不是物理的移动。。只改变指针我估计。。
现在,由于我还没有配置一个16 KB 的缓存,所以无法创建这样一个表空间。要解决这个问题,可以在以下方法中选择一种。我可以设置DB_16K_CACHE_SIZE 参数,并重启数据库。也可以缩小另外的某个SGA组件,从而在现有的SGA 中腾出空间来建立一个16 KB 的缓存。或者,如果SGA_MAX_SIZE 参数大于当前的SGA 大小,我还可以直接分配一个16 KB 的缓存。
注意从Oracle9i 开始,即使数据库已经启动并且正在运行,你也能重新设置各个SGA 组件的大小。如果你想拥有这个能力,能够“扩大”SGA 的大小(超过初始分配的大小),就必须把SGA_MAX_SIZE参数设置为大于已分配SGA 的某个值。例如,如果启动之后,你的SGA 大小为128 MB,你想再为缓冲区缓存增加另外的64 MB,就必须把SGA_MAX_SIZE 设置为192 MB 或更大,以便扩展。
在这个例子中,我采用收缩的办法,即缩小我的DB_CACHE_SIZE,因为目前这个参数设置得太大了:
ops$tkyte@ORA10G> show parameter db_cache_size
NAME TYPE VALUE
------------------ ----------- ----------------------
db_cache_size big integer 1G
ops$tkyte@ORA10G> alter system set db_cache_size = 768m;
System altered.
ops$tkyte@ORA10G> alter system set db_16k_cache_size = 256m;
System altered.
ops$tkyte@ORA10G> create tablespace ts_16k
datafile size 5m blocksize 16k;
Tablespace created.
这样一来,我就建立了另外一个缓冲区缓存,要用来缓存16 KB 大小的块。默认池(由db_cache_size参数控制)大小为768 MB,16 KB 缓存(由db_16k_cache_size 参数控制)大小为256 MB。这两个缓存是互斥的,如果一个“填满”了,也无法使用另一个缓存中的空间。这样DBA 就能很精细地控制内存的使用,但是这也是有代价的。代价之一就是复杂性和管理。使用多个块大小的目的并不是为了性能或作为一个调优特性,而是为了支持可传输的表空间,也就是可以把格式化的数据文件从一个数据库传输或附加到另一个数据库。比如说,通过实现多个块大小,可以取得一个使用8 KB 块大小的事务系统中的数据文件,并将此信息传输到使用16 KB 或32 KB 块大小的数据仓库。不过,对于测试来说,有多个块大小很有好处。如果你想看看你的数据库如何处理另一个块大小,例如,如果使用4 KB 的块而不是8 KB 的块,一个表会占用多大的空间。现在由于可以支持多个块大小,你就能很轻松地进行测试,而不必创建一个全新的数据库实例。还可以把多个块大小用作一种精细调优工具,对一组特定的段进行调优,也就是为这些段分配各自的私有缓冲区池。
数据库读取数据的最小单位是oracle数据块。还有一个问题就是oracle中有很多的”读“ 什么物理读,逻辑读之类的,目前我知道的内存内的叫逻辑读,读磁盘的叫物理读,以后再随时补充吧。
还有一个问题就是哪个进程将数据文件读到了buffer catch?
oracle里面有一些最繁忙的进程叫server process 进程,每一个用户连接到oracle数据库服务器的时候(一个session建立),oracle在后台会给每一个用户起一个server process进程,当这个用户的一条sql语句发过来,就只这一个server process进程拿着这个语句去shared pool里面做的解析,生成执行计划,然后再由他去数据文件里把需要的块读入buffer catch中,再由他把执行结果返回给用户。。。既然server process做这么多得工作,那肯定也需要一定的内存(工作室)来处理数据,恩,这就是PGA了,PGA就是这个前台进程和后台进程的内存区,当然后台进程用的比较少。
视图v$db_catch_advice由oracle自动根据一些数据模型算法,收集信息后产生一系列的值,作为调整data buffer 的参考。
shared pool:关注这么几个问题:
1、一条语句进来后如何找是否已经被解析过?
2、如何生成这个sql语句的执行计划的问题?
3、如何在shared pool中找到空闲的空间存储执行计划?
4、为了解析这个sql语句,肯定需要访问数据字典,数据字典在哪呢,在system表空间中,对应的物理文件就是system01.dbf文件。这就需要从这个文件上将数据字典块读到data buffer catch中,然后shared pool 从数据缓冲区中抽取需要的数据?
一个sql语句解析(花费老多cpu的时间),将解析好的语句和生成的执行计划都会放在shared pool中。所以可以认为shared pool中有两类信息,一类就是前面说的编译好的sql语句和执行计划,另一类就是数据字典缓冲区(data dictionary catch)的数据字典信息。
共享池的特点是有大量小的内存块(chunk),一般为4 KB 或更小。要记住,4 KB 并不是一个硬性限制,可能有的内存分配会超过这个大小,但是一般来讲,我们的目标是使用小块的内存来避免碎片问题。如果分配的内存块大小显著不同(有的很小,有的却相当大),就可能出现碎片问题。共享池中的内存根据LRU(最近最少使用)的原则来管理。在这方面,它类似于缓冲区缓存,如果你不用某个对象,它就会丢掉。为此提供了一个包,名叫DBMS_SHARED_POOL,这个包可用于改变这种行为,强制性地“钉住”共享池中的对象。可以使用这个过程在数据库启动时加载频繁使用的过程和包,并使它们不至于老化。不过,通常如果过一段时间共享池中的一段内存没有得到重用,它就会老化。甚至PL/SQL 代码(可能相当大)也以一种分页机制来管理,这样当你执行一个非常大的包中的代码时,只有所需的代码会加载到共享池的小块中。如果你很长时间都没有用它,而且共享池已经填满,需要为其他对象留出空间,它就会老化。
设计共享池是为了反复使用查询计划。如果每个查询都是全新的,都是以前从来没有见过的查询,那么缓存只会增加开销。共享池反而会损害性能。为了解决这个问题,很多人都会用一种看似合理的常用技术,也就是向共享池增加更多的空间,但是这种做法一般只会使问题变得比以前更糟糕。由于共享池不可避免地会再次填满,比起原来较小的共享池来说,开销甚至更大,原因很简单,与管理一个较小的满共享池相比,管理一个大的满共享池需要做更多的工作。对于这个问题,真正的解决方案只有一个,这就是使用共享SQL,也就是重用查询。在前面(第1 章),我们简要介绍了参数CURSOR_SHARING,在这方面,游标共享可以作为一种短期的解决方案。不过,真正要解决这个问题,首当其冲地还是要使用可重用的SQL。即使在最大的系统上,我发现一般也最多有10 000~20 000 条不同的SQL 语句。大多数系统只执行数百个不同的查询。
对于间歇性访问的比较大的对象,例如自定义的过程与包,如果在运行过程中不想被系统调换出去,可以采用DBMS_SHARED_POOL.KEEP这个存储过程将该过程或者包pin在共享池中。
我们可以用一下命令手工清除共享池的内容:
alter system flush shared pool;
在oracle9i之前的版本中共享池的sum(bytes)结果与shared_pool_size是没有关系的,但是10g以后中这两个值变得相等了,可以分别查询之:
select sum(bytes) from v$sgastat where pool='shared pool';
show parameter shared_pool_size;
big pool:之所以叫大池,是因为这个池是用来做大块内存的分配(要知道shared pool不能做大块内存的处理),共享池是采用LRU列表管理的,这种管理方式对于缓存或者重复使用数据块很合适,但是,对于大池,一般都是分配一块大的内存用来给UGA使用,当一个用户的session断了之后,此块内存就会直接收回,这样用LRU算法并不合适;
在共享池中,实际上没有释放内存块的概念。你只是分配内存,然后使用,再停止使用而已。过一段时间,如果需要重用那个内存,Oracle 会让你的内存块老化。如果只使用共享池,问题在于:一种大小不一定全局适用。
大池主要用于如下三个方面:
1)共享服务器连接方式中,在SGA中分配UGA区,就在大池中分配。
2)在并行查询中,允许大池分配进程间的消息缓冲区,这些缓冲区用于协调并行查询服务器。
3)rman备份中用于磁盘的 I/O 缓冲区。
data dictionary:数据库里有两类信息,一类就是数据字典信息,包括这个数据库内有多少表,多少索引,每个表有多少列,每个列的名字等等等,详细信息,都以表的形式存储在system表空间中;另一类就是生产数据啦。