SGA(SYSTEM Global Area )系统全局区
l 数据快速缓存
在Oracle进行数据处理的过程中,代价最昂贵的就是物理 I/O操作了。相同的数据从内存中得到要比从磁盘上读取快的多。
因此。优化Oracle的一个重要的目标就是尽可能的减少物理 I/O操作。
Oracle的 Buffer Cache用于缓存从磁盘中读取的数据。当 Oracle须要查找某些信息的时候,首先会在 BufferCache中寻找。假设找到了。则直接将结果返回。假设找不到,则须要对磁盘进行扫描, Oracle将在从磁盘扫描得到的结果返回的同一时候。会把这些数据在Buffer Cache中也保留一份,假设下次须要訪问同样的数据块的时候,则不须要再次扫描磁盘,而是直接从 Buffer Cache中读取就可以。
² 数据快速缓存由初始化參数DB_CACHE_SIZE指定大小,由很多大小相等的缓存块组成,这些缓存块的大小和OS块大小同样。这些缓存块分为 3 大类:
n 脏缓存块(Dirty buffers ):
脏缓存块中保存的已被改动过的缓存块。即当一条SQL语句对某个缓存块中的数据进行改动后,该缓存块就被标记为脏缓存块。
最后。脏缓存块被DBWn进程写入到硬盘的数据文件里,永久保留起来。
n 命中缓存块(Pinned buffers ):
命中缓存块中保存的是近期正在被訪问的缓存块。它始终被保留在数据快速缓存中,不会被写入数据文件。
n 空暇缓存块(Freebuffers):
该缓存块中没有数据。等待被写入数据。
oracle从数据文件里读取数据后,寻找空暇缓存块,以便写入当中。
² 标准数据库缓冲区缓存分为下面三种:
n 保持(keep)缓冲池:长期保存在内存中,直到数据库被关闭为止,其大小由BUFFER_POOL_KEEP指定。
n 再生(recycle)缓冲池:数据一旦用毕后就被换出内存中,其大小由BUFFER_POOL_RECYCLE指定。
n 默认(default)缓冲池:数据使用LRU调度算法来换出。其大小由DB_CACHE_SIZE 决定。
² 工作原理和过程LRU(近期最少使用 Least Recently Used )。Oracle通过 2 个列表(DIRTY、LRU)来管理缓存块。
n DIRTY 列表中保存已经被改动但还没有被写入到数据文件里的脏缓存块。
n LRU 列表中保存还没有被移动到DIRTY列表中的脏缓存块、空暇缓存块、命中缓存块。当某个缓存块被訪问后。该缓存块就被移动到LRU列表的头部(Most Recent Used, MRU端),其它缓存块就向LRU列表的尾部(Least Recently Used, LRU 端)移动。放在最尾部的缓存块就最先被移出LRU列表。
说明:假设用户运行的是全表扫描的操作,这些操作产生的数据缓冲不会放到 LRU端的 MRU端,而是放到LRU端。
由于Oracle觉得全表扫描得到的数据仅仅是临时的须要,这些数据以后被重用的机会非常少,应该高速的清除出缓冲区。把空间留给其它的更经常使用的数据。
能够在表的级别上改变这样的处理方式。
在建表的时候指定Cache语句会使得这张全表扫描得到的数据也放在 LRU链表的 MRU端。
n 数据快速缓存的工作原理过程是:
A、ORACLE在将数据文件里的数据块拷贝到数据快速缓存中之前,先在数据快速缓存中找空暇缓存块。以便容纳该数据块。Oracle 将从LRU列表的尾部開始搜索,直到找到所需的空暇缓存块为止。
B、假设先搜索到的是脏缓存块,则将该脏缓存块移动到DIRTY列表中,然后继续搜索。
假设搜索到的是空暇缓存块,则将数据块写入。然后将该缓存块移动到DIRTY列表的头部。
C、假设可以搜索到足够的空暇缓存块。就将全部的数据块写入到相应的空暇缓存块中。
则搜索写入过程结束。
D、假设没有搜索到足够的空暇缓存块。ORACLE就先停止搜索,激活DBWn进程。開始将DIRTY列表中的脏缓存块写入到数据文件里。
E、已经被写入到数据文件里的脏缓存块将变成空暇缓存块。并被放入到LRU列表中。
运行完毕这个工作后,再又一次開始搜索,直到找到足够的空暇缓存块为止。
² KEEP池和 RECYCLE池的使用
假设内存足够大,能够容纳全部的数据,则訪问不论什么数据都能够从内存中直接获得,那么效率肯定是最高的。可是在实际应用其中,常常是数据库的大小达到了几百个 GB甚至是几个 TB,而 Oralce的可用内存仅仅有几个 GB大小。缓存中缓存的数据仅仅能占到整个数据库数据的非常小一部分,因此。这就要求必须合理的分配内存的使用。
假设可使用的内存空间比較小,导致数据库缓冲区的命中率比較低,则能够通过配置 KEEP池和 RECYCLE池,把性质不同的表分离到不同的数据缓冲区,以提高命中率,减少此操作对正常訪问的影响。
默认情况下,全部的表都是用 default池,它的大小就是缓冲区Buffer Cache的大小,由初始化參数 db_cache_size来决定。假设在建表或者改动表的时候指定 STORAGE(BUFFER_POOLKEEP)或者 STORAGE(BUFFER_POOLRECYCLE)语句,就设置这张表使用 KEEP或者 RECYCLE缓冲区。这两个缓冲区的大小分别由初始化參数 db_keep_cache_size和db_recycle_cache_size来决定。
通过以下的sqlplus命令查看带“cache_size”字符串的系统參数值
SQL> show parametercache_size
结果例如以下:
db_16k_cache_size big integer 0
db_2k_cache_size big integer 0
db_32k_cache_size big integer 0
db_4k_cache_size big integer 0
db_8k_cache_size big integer 0
db_cache_size big integer 0 --属于SGA自己主动管理组件,值为0.
db_keep_cache_size big integer 0
db_recycle_cache_size big integer 0
SQL> alter system set db_keep_cache_size=16Mscope=both;
SQL> alter system setdb_recycle_cache_size=16M scope=both;
SQL> show parametercache_size
db_16k_cache_size big integer 0
db_2k_cache_size big integer 0
db_32k_cache_size big integer 0
db_4k_cache_size big integer 0
db_8k_cache_size big integer 0
db_cache_size big integer 0 --属于 SGA自己主动管理组件。值为0.
db_keep_cache_size big integer 16M
db_recycle_cache_size big integer 16M
n KEEP池
KEEP池用来缓存那些常常会被訪问的表。
KEEP池使用缓冲区独立于DEFAULT池。因此把最常常使用的表缓存到单独的缓冲区中,使得数据库的其它操作。如运行大量批操作也不会影响到这些在 KEEP缓冲区中的表。保证訪问这些最常使用的表的数据时,都能够从内存中直接获得。
SQL> col name format a30
SQL> col value format a30
SQL> conn scott/scott
SQL> create tabletest_default(col number(3)) storage(buffer_pool default);
SQL> create tabletest_keep(col number(3)) storage(buffer_pool keep);
SQL> create table test_recycle(colnumber(3)) storage(buffer_pool recycle);
SQL> insert intotest_default values(1);
SQL> insert into test_keepvalues(1);
SQL> commit;
SQL> set autotrace on statistics
SQL> select * fromtest_default;
统计信息
1 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> select * fromtest_keep;
统计信息
1 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> show sga
Total System Global Area 528482304 bytes
Fixed Size 1249944 bytes
Variable Size 150998376 bytes
Database Buffers 369098752 bytes
Redo Buffers 7135232 bytes
SQL> select369098752/1024/1024 from dual; --计算DatabaseBuffers的大小为352M
在上面的样例中,建立了两张表。 Test_default指定默认的default池,test_keep指定了keep池。分别插入了一条数据,然后打开自己主动跟踪,对这两张表进行查询。因为刚刚运行了 INSERT语句,这两条数据都存放在各自的缓冲区中。因此查询的物理读(physical reads)为 0。接着查看 buffer cache的值,发现大小为352M,SGA为 504M。
以下构造一个较大的批操作,插入的数据大于 504M,将 default区域覆盖掉。
SQL> create tabletest_eat_memory (col1 varchar2(4000), col2 varchar2(4000), col3 varchar2(4000),col4 varchar2(4000), col5 varchar2(4000), col6 varchar2(4000), col7varchar2(4000), col8 varchar2(4000), col9 varchar2(4000), col10 varchar2(4000))storage(buffer_pool default);
SQL> insert intotest_eat_memory select rpad('1',4000,'1'), rpad('2',4000,'2'), rpad('3',4000,'3'),rpad('4',4000,'4'),rpad ('5',4000,'5'), rpad('6',4000,'6'), rpad('7',4000,'7'),rpad('8',4000,'8'), rpad('9',4000,'9'), rpad('0',4000,'0') from all_objectswhere rownum<=15000; --插入15000行数据
统计信息
10410 recursive calls
564195 db block gets
108584 consistent gets
620 physical reads
637527688 redo size --大约插入了638M数据
678 bytes sent via SQL*Net to client
803 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
91 sorts (memory)
0 sorts (disk)
15000 rows processed
SQL> commit;
运行完批操作后,对两张表再次查询。
SQL> select * fromtest_default;
统计信息
70 recursive calls
0 db block gets
13 consistent gets
12 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> select * fromtest_keep;
统计信息
70 recursive calls
0 db block gets
13 consistent gets
0 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
rows processed
SQL> show sga
Total System Global Area 528482304 bytes
Fixed Size 1249944 bytes
Variable Size 150998376 bytes
Database Buffers 369098752 bytes --default区域没有变化
Redo Buffers 7135232 bytes
结果非常明显。因为 keep和 default池彼此独立,对于 test_keep的查询的物理读仍然为0,而对 test_default的查询则包括了12个物理读。
上面的样例能够看出,使用 keep池能够保证那些指定 keep池的表不受其它表的影响。
能够查询v$bh视图来查找到常常被使用的表,依据表的使用频繁度来确定是否指定 keep池。
select o.object_name, count(*)from dba_objects o, v$bh bh where o.object_id = bh.OBJD and o.owner != 'SYS'group by o.object_name having count(*) > 100 order by count(*) desc
确定好使用 keep池的表后,能够依据这些表的实际大小之和来计算缓冲区的大小。因为这个大小能够比較准确的计算出来。因此能够对这些表使用 cache,以保证即使採用全表扫描得到的数据也能够被缓冲。
通常情况下,并不追求 keep池的命中率达到 100%,假设命中率为 100%,则说明给 keep池的内存空间过大。有部分内存被浪费。
即使 keep池中缓存的都是些最常常訪问的表。这些訪问操作也不大可能訪问到表中全部的数据。
因此,能够适当的降低 keep池的内存分配,使 keep池的命中率维持在接近 100%的数值。
将这部分内存分配给其它的缓冲区。能够得到更高的效率。
能够採用以下的SQL语句来计算 KEEP池的命中率。
SQL> select name,physical_reads, db_block_gets, consistent_gets, 1 -(physical_reads /(db_block_gets + consistent_gets)) "hit ratio" fromv$buffer_pool_statistics where name = 'KEEP';
n RECYCLE池
RECYCLE池用来缓存那些不希望保存在内存中的表。比如非常少进行扫描或者訪问的表。假设应用程序以一种随机的方式訪问一张比較大的表,这些被缓冲的数据在被清除出内存之前,非常少会有机会再次被訪问。这些数据存放在缓冲区其中,不仅会浪费内存空间,并且可能把其它的一些有可能被訪问的数据清除出去。
这些数据不是必需保存在缓冲区其中。能够通过使用 RECYCLE池来避免这些数据对其它数据的影响。
调整參数db_recycle_cache_size的大小来设置recycle池。一般来说。不须要给 recycle池非常大的内存空间。由于recycle池中的数据没有什么被缓存的价值。设置较小的缓冲区能够将很多其它的内存留给keep 和default池。
可是。假设缓冲区太小的话,数据可能在事务结束之前就从内存从中被清除了,这会导致额外的性能问题。
SQL> truncate tabletest_eat_memory;
SQL> select * fromtest_default;
统计信息
0 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> alter tabletest_eat_memory storage(buffer_pool recycle);
SQL>insert intotest_eat_memory select rpad('1',4000,'1'), rpad('2',4000,'2'), rpad('3',4000,'3'),rpad('4',4000,'4'),rpad ('5',4000,'5'), rpad('6',4000,'6'), rpad('7',4000,'7'),rpad('8',4000,'8'), rpad('9' ,4000,'9'), rpad('0',4000,'0 ) from all_objectswhere rownum<=15000; --插入15000行数据
统计信息
10410 recursive calls
564195 db block gets
108584 consistent gets
620 physical reads
637527688 redo size --大约插入了638M数据
678 bytes sent via SQL*Net to client
803 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
91 sorts (memory)
0 sorts (disk)
15000 rows processed
SQL> commit;
SQL> select * fromtest_default;
统计信息
70 recursive calls
0 db block gets
0 consistent gets
12 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
rows processed
在这个样例中。将进行批操作的表改为recycle池。在批操作运行完毕后,发现 test_default表的数据仍然能够在default池中找到。
这样的方法屏蔽了批操作对系统的影响。
小结
对于大多数的系统而言,使用 default池就够了。
可是假设内存空间相对较小,或者对系统中表的使用情况有比較清晰的认识,则能够通过配置 keep池和 recycle池来细化内存的分配。提高数据缓冲区的命中率,减少批操作对系统的影响。
尽管 keep池、recycle池用来缓存不同类型的数据。可是他们的机制是同样的。他们採用的都是LRU算法。假设keep池分配的内存不足,那么也会有部分数据被清除出内存;假设 recycle池的内存分配足够,也能够保证当中的数据所有缓存。从本质上讲。 keep池和 recycle池并没有什么差别,仅仅是名字不同而已。
假设给 keep池或者 recycle池分配的内存大小不合适,不但不会提高性能,并且会造成性能的下降。以 keep池为例。内存分配小了。这些常常被訪问的、数据就会有部分被清除出内存。导致命中率降低。假设内存分配过大。则导致 default池内存要对应的降低,default池不仅包含用户部分数据。并且也包含数据字典的缓冲。
因此。 default池内存的不足。必定导致整个系统性能的下降。并且,因为真实环境中,全部的表的大小都处于变化之中,因此,须要常常对不同缓冲区的命中率进行检查,并随时调整缓冲区的大小以满足数据不断变化的须要。
l 重做日志快速缓存
² 重做日志快速缓存大小由初始化參数LOG_BUFFER指定,能够在执行期间改动该參数。
² 工作原理:为了加快訪问速度和工作效率,重做记录并不直接写入重做日志文件里,而是首先从数据快速缓存写入重做日志快速缓存。
当重做日志快速缓存中的重做记录达到一定数量或某个时间点时,再由LGWR进程分批写入重做日志文件里(即ORACLE 总是先日志后文件或先内存后磁盘)。
因为重做日志文件是循环使用的。所以当重做日志文件切换时,还会由ARCn(假设启用了归档日志模式)进程将即将要被覆盖的重做日志文件里的数据写入到归档日志文件里,作为备份。
SHOWPARAMETER LOG_BUFFER; ------查询重做日志缓存的大小
SELECT* FROM V$SYSSTAT; ------查询用户进程等待重做日志缓存的次数。
l 共享池
² 共享池由初始化參数SHARED_POOL_SIZE指定,默认80MB。能够在执行期间手动改动该參数。
² 共享池中保存了近期运行的SQL语句、PL/SQL过程与包、数据字典信息、锁、以及其它控制结构的信息。共享池是对SQL语句、PL/SQL程序进行语法分析、编译、运行的内存区。共享池又分为两部分:
n 数据字典缓存
ü 数据字典缓存用于存储常常使用的数据字典信息。比方:表的定义、username、口令、权限、数据库的结构等。
ü Oracle执行过程中常常訪问该缓存以便解析SQL语句,确定操作的对象是否存在,是否具有权限等。假设不在数据字典缓存中。server进程就从保存数据字典信息的数据文件里将其读入到数据字典缓存中。
数据字典缓存中保存的是一条一条的记录(就像是内存中的数据库)。而其它缓存区中保存的是数据块信息。
n 库缓存
ü 库缓存大小与OPEN_CURSOR初始化參数相关,ORACLE中每条查询语句都须要打开一个游标。OPEN_CURSOR默认值为300。
ü 库缓存的目的就是保存近期解析过的SQL语句、PL/SQL过程和包。
这样一来。Oracle在运行一条SQL语句、一段PL/SQL 过程和包之前。首先在“库缓存”中搜索。假设查到它们已经解析过了,就利用“库缓存”中解析结果和运行计划来运行。而不必又一次对它们进行解析,显著提高运行速度和工作效率。
² Oracle长期执行后,共享池可能出现碎片,这时能够用下面语句清除共享池内的所有数据:alter system flush shared_pool;
² 实验与案例
n 验证数据块缓存和共享池的作用
1. 用sys登陆sqlplus,运行统计用户表空间个数的语句。
SQL>conn / as sysdba
SQL>set timing on
SQL>select count(*) from user_tablespaces;
因为是第一次运行该查询,须要将外存的user_tablespaces信息读入数据块缓存并对其进行解析,再把解析结果存储到共享池的库缓存中,所以用时较多。
2. 第二次运行该查询。
因为不须要读外存,且sql语句运行计划在内存中,不须要硬解析,速度较快。
SQL>select count(*) from user_tablespaces;
3. 清空共享池,第三次运行。因为清除了共享池。须要又一次解析sql语句,但所需数据还在数据库块缓存中,所以用时介于两者之间。
SQL>select count(*) from user_tablespaces;
n 缓存命中率
ü 逻辑读(LogicalReads):即从缓存中读取数据。
ü 物理读(PhysicalReads):即从物理磁盘上读取数据。
SQL>select statistic#, name, value from v$sysstat where name in ('physical reads', 'dbblock gets', 'consistent gets')
说明:v$sysstat是用来动态跟踪系统性能參数的数据字典表。
查询和计算命中率有关的三个数据库行,各自是physical reads, db block gets, consistent gets。当中db block gets和 consistentgets的value值相加数据值为全部读的总次数。逻辑读次数为总和减去physical reads的value值。命中率为:逻辑读次数/全部读的总次数。
l 大池
² 由初始化參数LARGE_POOL_SIZE确定大小。能够使用ALTER SYSTEM语句来动态改变大池的大小。
² 大池是可选项的,DBA能够依据实际业务须要来决定是否在SGA区中创建大池。假设创建,将会自己主动的被各种各样的进程拿来使用。本来这些进程是使用共享池的内存。假设没有创建大池,则须要大量内存空间的操作将占用共享池的内存。
² ORACLE 须要大力内存的操作有:
A、数据库备份和恢复。
B、具有大量排序操作的SQL语句。
C、并行化的数据库操作。
l JAVA池
² 由初始化參数JAVA_POOL_SIZE确定大小,控制在30-50MB比較合适。
² 用户存放JAVA代码、JAVA语句的语法分析表、JAVA语句的运行方案和进行JAVA程序开发。
² 能够使用ALTER SYSTEM SET JAVA_POOL_SIZE=0M SCOPE=SPFILE;调整其大小。语句在server初始化參数文件里改动该參数。必须又一次启动数据库server才干使其生效。