Oracle9i为Oracle数据库引擎带来了一些令人吃惊的复杂性。它推出了许多新的内部特性,包括bitmap free lists,基于redo log的复制,动态SGA,还有一个可能是最重要的特性,可以支持多种块大小(Block Size)。
当你忽略全部的高级特性时,Oracle的工作就是传送数据,磁盘的I/O管理和调整对于任何的Oracle数据库都是一个重要的部分。任何可以令磁盘I/O减少的工作都对Oracle数据库系统有一个正面的影响。
如果我们查看一下各种各样调整Oracle数据库性能的方法,就会发现其实Oracle性能调整的共同目标都是减少磁盘的I/O。例如,调整一个SQL语句以除去一个全表搜索的操作可以令查询运行得更快,因为这样可以直接地减少需要由磁盘上读取的数据块。调整实例的参数,例如DB_CACHE_SIZE也可以减少磁盘的开销。
要理解怎样使用多种块大小来提升Oracle数据库的性能,我们首先查看一下磁盘I/O的基本特性。任何时候由磁盘上访问一个Oracle数据块时,我们通常会见到三种延迟。第一种也是最重要的延迟来源于读-写头的移动时间。这个时间是指读-写头需要将自己定位到正确的柱面所需要的时间。还有选择延迟的时间,这是读-写头等待相应的块出现在它的下面,第三个延迟来源于将数据由磁盘传回到Oracle SGA。
其实99%的延迟都是在真正访问实际数据块前发生的,那么我们就可以知道读取一个32K的块所需要的时间其实和读取一个2K大小的块相差不大。也就是说,磁盘的延迟时间都是差不多的,它和块的大小无关。因此我们可以得出这样的结论:如果每次I/O都能够读取最大的块,那么Oracle数据库所需要的整体I/O就会变少。
缓冲的原理并不是Oracle数据库特有的。对于内存的访问是以纳秒计算的,而对磁盘的访问通常是用毫秒计算的。如果我们可以将Oracle的数据块都放入磁盘的缓冲中,性能将有着很大的提升。随着Oracle的成熟和内存变得越来越便宜,我们将会发现Oracle数据库的系统全局空间(SGA)的大小通常都超过10GB。这样对于Oracle数据库的性能有着很大的提升,因为在读取时,Oracle数据块都处在内存中,相对于需要由磁盘上得到数据块,这样将会快成千上万倍。
内存缓冲中保留着Oracle访问过的数据块,在缓冲中的数据读取速度要比由磁盘中读取要快14,000倍。内存数据缓冲已经由Oracle7的单一缓冲发展为Oracle8i中的三个数据缓冲。它们的名字分别是KEEP pool,RECYCLE pool和 DEFAULT pool(如图1所示)。
****************图一***************
Oracle数据缓冲
在Oracle9i中我们仍然有三个数据缓冲,不过我们还可以为Oracle服务器支持的每个块大小创建一个数据缓冲(如图2所示)。
************图2-Oracle9i的8个数据缓冲*******
在每个数据缓冲中,由数据缓冲的命中率可以知道一个数据块处在内存中的可能性。在数据缓冲间分配内存页以确保内存缓冲的最优利用是Oracle管理员的工作。有时通过增加一些缓冲就有明显的效果(见图3)
************图三***************
(增加到一个小的数据缓冲的内存页)
随着内存缓冲的增加,增加页面带来的好处就会下降(如图4所示)。
**************图4***************
在大的数据缓冲下,由此而带来的好处下降
索引和大的数据块
在Oracle9i前,Oracle的专家发现通过将整个数据库移植到更大的数据块,可以减少磁盘的I/O,从而令整个系统的性能得到提升。由表面看来这有点不符合常理,人们可能会问"如果我只需要一个80字节的行,那么读取16K的块又有什么好处呢?"
这个问题的答案和索引有关。大部分经过很好地调优的Oracle数据库都拥有和表数据差不多大小的索引。对于索引来说,大的数据块无疑可以减少I/O,从而可以提升整个数据库的性能。
所以,Oracle9i数据库管理员要做的第一件事可能就是创建一个32K的表空间,一个相应的32K大小的数据缓冲,然后将他们系统中的全部索引移植到这个32K的表空间中。通过这样,Oracle9i数据库就可以在一次磁盘I/O中读取相当数量的索引节点分枝,因此可以减轻系统的压力并且提高总体的性能。
将对象分配到多个块缓冲中
通过这种方式,我们就可以在Oracle数据库创建多个数据缓冲,那么我们怎样决定放些什么数据到这些数据缓冲中呢?
让我们先来看一些更常见的技巧。
隔离大表的全表搜索--对于要进行全表搜索的大表将会从最大的块大小中得益,它们应该被放在使用最大块大小的表空间。
仔细设置db_recycle_cache_size--如果你没有为服务器设置db_cache_size到支持的最大块大小,你将不应该使用db_recycle_cache_size参数。代替的是,你将要创建一个db_32k_cache_size(或者是你设置的最大值),并且将那些经常需要进行全表搜索的大表分配到最大的缓存中。
数据字典(Data Dictionary)使用默认的缓冲--你应该确保数据字典(例如你的SYSTEM表空间)经常全部缓冲到一个数据缓冲池中。要记住,确保SYSTEM表空间的数据缓冲拥有足够的内存来缓冲全部的数据字典块要比数据字典的块大小重要。
隔离索引--在许多情况下,Oracle的SQL语句将会通过一个索引范围搜索来得到索引的信息,根据SQL语句的条件,通过b树或者bitmap索引来搜索一定范围的值。因此,将尽量多的索引放到内存中是有好处的。Oracle 9i数据库管理员首先要做的其中一件事情就是将他们全部的Oracle索引转移到一个使用大的数据块的表空间中,索引性能将会由大的块中得到好处。
隔离随机访问读取--对于那些由磁盘中随机读取很少行数的数据库来说,Oracle DBA可以移动这些类型的表到一个2K的表空间中。我们要记住,虽然磁盘已经越来越便宜,但是这样做会读取一些与查询无关的内容到内存中,这是我们不希望看到的。因此,对于小的、随机访问的表,Oracle DBA通常使用小的块大小。
隔离LOB列的表--对于那些包含有raw, long raw或者in-line LOBs的表,将它们移动到大的数据块中将会极大地提升磁盘I/O的性能。有经验的DBA将会检查dba_tables.avg_row_len来确保块大小要比平均的行大。这样将可以减少Row chaining的发生,同时整个LOB都可以在一次磁盘I/O中读取,避免了Oracle必须读取多个块而带来的开销。
隔离全表搜索的大表--在Oracle8i中首次推出recycle pool,它的想法是全表搜索的数据块通常都不会被其它事务重新读取),从而可以将它们快速地由Oracle SGA中清除,这样就可以将宝贵的内存用在那些有更大机会被其它事务重新读取的数据块上。在Oracle9i中,你可以设置recycle pool使用一个更小的块大小。
检查平均的行长--表空间的块大小要比其中表的平均行长要大(dba_tables.avg_row_len)。如果它比平均行长小,这时就会发生rows chaining和过多的磁盘I/O。
使用大的块作数据排序--你的TEMP表空间将会由最大支持的块中受益。这样磁盘排序句可以发生在大的块中,从而减少磁盘I/O。
查看数据缓冲使用情况的工具
将Oracle对象放到独立的数据缓冲中的过程是很简单的,Oracle9i还提供了一些工具作辅助。许多Oracle的管理员都没有意识到这些处于数据缓冲中的块消耗一个不对称的数据空间,而Oracle9i提供了大量的脚本来让你查看哪些对象是经常处在数据缓冲中的。
以下的查询是用来计算当前缓冲中的全部segment的块数目。根据你的缓冲大小,这样或者需要很多排序空间。
column object_name format a40
column number_of_blocks format 999,999,999,999
column object_name format a40
column number_of_blocks format 999,999,999,999
SELECT
o.object_name,
COUNT(1) number_of_blocks
FROM
DBA_OBJECTS o,
V$BH bh
WHERE
o.object_id = bh.objd
AND
o.owner != 'SYS'
GROUP BY
o.object_name
ORDER BY
count(1) desc;
以下让我们看一下缓冲中的对象名和数据块的数目
OBJECT_NAME NUMBER_OF_BLOCKS
---------------------------------------- ----------------
ORDER_TABLE 123,273
ORDER_IDX 112,492
CUSTOMER 83,272
. . .
OEM_EXT 701
创建独立的数据缓冲
在Oracle9i中,将表或者索引块分配到不同数据块大小的表空间是很简单的。在创建一个表空间时,我们会使用一个新的blocksize参数。在以下的例子中,我们在Oracle数据库中创建了一个32K的表空间。
create tablespace
32k_tablespace
datafile
'/u01/oradata/mysid/32k_file.dbf'
size
100M
blocksize
32k
;
我们一旦创建了表空间,下一步是根据上面的blocksize来设置一个数据库缓冲。要记住,Oracle 9i不再使用init.ora文件,所以我们要通过alter database语句来动态地创建带名字的缓冲。
alter system set db_2k_cache_size=200M;
alter system set db_4k_cache_size=500M;
alter system set db_8k_cache_size=800M;
alter system set db_16k_cache_size=1600M;
一旦我们创建了带名字的内存缓冲和表空间,我们就可以将Oracle对象转移到新的表空间中。对于将对象由一个表空间转移到另一个,有多种方法,而许多的Oracle管理员已经习惯使用create table as select or CTAS语法来移动表格。对于index,则可以使用alter index rebuild转移到另一个表空间。
结论
对于Oracle9i的许多新特性,许多有经验的DBA都认为块的大小对于调整Oracle数据库是最重要的。管理员现在可以使用多达7个独立和不同的数据池,可以对每个数据对象使用的数据缓冲块的数目进行更大的控制。通过考察不同的缓冲访问特性,可以大大地减少磁盘I/O,从而极大地提高数据库的性能。