先看看Oracle文档上对db_block_checking参数的说明:
DB_BLOCK_CHECKINGcontrols whether Oracle performs block checking for data blocks. When this parameter is set totrue, Oracle performs block checking for all data blocks. When it is set tofalse, Oracle does not perform. block checking for blocks in the user tablespaces. However, block checking for theSYSTEMtablespace is always turned on.
Oracle checks a block by going through the data on the block, making sure it is self-consistent. Block checking can often prevent memory and data corruption. Block checking typically causes 1% to 10% overhead, depending on workload. The more updates or inserts in a workload, the more expensive it is to turn on block checking. You should set
DB_BLOCK_CHECKING to true
if the performance overhead is acceptable
从文档中可以看到,DB_BLOCK_CHECKING参数主要是用于数据块的逻辑(一致)检查(但只是块内,不包括块间的逻辑检查,比如索引项目的ROWID指向的是不存在的行等)。主要用于防止在内存中损坏或数据损坏。由于是逻辑检查,因此引起的额外负荷比较高,甚至可以达到10%,因此对于一个繁忙的系统,特别是插入或更新操作很多的系统,性能影响是比较明显的。
该参数对SYSTEM表空间始终是处于“打开”状态,而不管该参数是否设置为FALSE。
下面再看看db_block_checksum参数的说明:
DB_BLOCK_CHECKSUMdetermines whether DBWnand the direct loader will calculate achecksum(a number calculated from all the bytes stored in the block) and store it in the cache header of every data block when writing it to disk. Checksums are verified when a block is read-only if this parameter istrueand the last write of the block stored a checksum. In addition, Oracle gives every log block a checksum before writing it to the current log.
If this parameter is set tofalse, DBWncalculates checksums only for theSYSTEMtablespace, but not for user tablespaces.
Checksums allow Oracle to detect corruption caused by underlying disks, storage systems, or I/O systems. Turning on this feature typically causes only an additional 1% to 2% overhead. Therefore, Oracle Corporation recommends that you setDB_BLOCK_CHECKSUM to true
可以看到,DB_BLOCK_CHECKSUM只是在写入(DBWn常规写法或用户进程直接路径写入),根据一个CHECKSUM算法,计算数据块的校验和。然后写入数据块的一个特定位置(CACHE HEADER,具体是块的16-17字节,以0字节起算)。在读取块时,再进行检验。主要是防止IO硬件和IO子系统的错误。
CHECKSUM的算法只是根据块的字节值计算一个效验和,因此算法比较简单,引起的系统额外负荷通常在1%-2%
实际上,即使将该参数设为TRUE,将数据块(包括SYSTEM表空间)的16-17字节清0,同时将15字节(flag),第3位(即值为16进制
0x04)清为0,则在块读取时也不会做CHECKSUM检查。如果该参数为FALSE,对于除SYSTEM的其他表空间,如果原来有CHECKSUM
值,将15-16字节清0也不会做CHECKSUM检查。
上诉简要地描述了db_block_checking和db_block_checksum这两个参数的作用以及性能方面的影响。在10gR1及这前的版本中,这两个参数可以设置为false和true。而在10gR2版本中,这两个参数发生了一点变化。
先来看看db_block_checking,这个参数现在有四个可能的设置:
- OFF - 与原来的FALSE一样,对非SYSTEM表空间的块关闭检查,这个值在设置时仍然可以用false。
- LOW - 只检查块头。这个检查发生在当块的内容在内存中发生改变时,比如UPDATE、INSERT、DELETE等,以及将块从磁盘读入、RAC结点间块的传输。
- MEDIUM - 比LOW更高一级,还包括了非IOT的表的块内部检查(即不仅仅是块头)。
- FULL - 与原来的TRUE一样,与MEDIUM相比,还包括了索引块的检查。
再看看db_block_checksum这个参数有什么变化:
- OFF - 与原来的FALSE一样,只会给SYSTEM表空间的块计算checksum值。
- TYPICAL - 与原来的TRUE一样,Oracle在向磁盘写入块时计算checksum值,下次读入时进行校验。
- FULL - 这是新增的值,Oracle不关在写入块时计算checksum值,而且在更改块(比如执行UPDATE语句等)之前对checksum值进行校验,同时在更改块之后对checksum值进行重新计算。另外Oracle也会在写入日志块时,计算块的checksum。这个设置大大增加了系统负荷,大约带来了4-5%的负荷。而TYPICAL值会带来1-2%的负荷。
下面做个测试:
首先建一个测试表,并设置db_block_checking和db_block_checksum为false:
create table t2 (a int) tablespace test;
表已创建。
alter system set db_block_checking=false;系统已更改。
alter system set db_block_checksum=false;
向测试表T2中四次分别插入100,000行数据:
begin
for i in 1..100000 loop
insert into t2 values(i);
end loop;
end;
/PL/SQL 过程已成功完成。
已用时间: 00: 00: 06.02
commit;提交完成。
已用时间: 00: 00: 00.00
alter system checkpoint;系统已更改。
已用时间: 00: 00: 01.02
begin
for i in 1..100000 loop
insert into t2 values(i);
end loop;
end;
/PL/SQL 过程已成功完成。
已用时间: 00: 00: 05.04
commit;提交完成。
已用时间: 00: 00: 00.00
alter system checkpoint;系统已更改。
已用时间: 00: 00: 01.02
begin
for i in 1..100000 loop
insert into t2 values(i);
end loop;
end;
/PL/SQL 过程已成功完成。
已用时间: 00: 00: 07.04
commit;提交完成。
已用时间: 00: 00: 00.00
alter system checkpoint;系统已更改。
已用时间: 00: 00: 01.01
begin
for i in 1..100000 loop
insert into t2 values(i);
end loop;
end;
/PL/SQL 过程已成功完成。
已用时间: 00: 00: 07.04
commit;提交完成。
已用时间: 00: 00: 00.00
alter system checkpoint;系统已更改。
已用时间: 00: 00: 01.01
四次数据插入中,最长的时间为7.04秒,最短时间为5.05秒,平均6.29秒。
下面再看看将这两个参数设置为true的测试结果:
alter system set db_block_checking=true;
系统已更改。
alter system set db_block_checksum=true;
系统已更改。
begin
for i in 1..100000 loop
insert into t2 values(i);
end loop;
end;
/PL/SQL 过程已成功完成。
已用时间: 00: 00: 11.02
commit;提交完成。
已用时间: 00: 00: 00.00
alter system checkpoint;系统已更改。
已用时间: 00: 00: 01.02
begin
for i in 1..100000 loop
insert into t2 values(i);
end loop;
end;
/PL/SQL 过程已成功完成。
已用时间: 00: 00: 12.01
commit;提交完成。
已用时间: 00: 00: 00.00
alter system checkpoint;系统已更改。
已用时间: 00: 00: 01.02
begin
for i in 1..100000 loop
insert into t2 values(i);
end loop;
end;
/PL/SQL 过程已成功完成。
已用时间: 00: 00: 09.00
commit;提交完成。
已用时间: 00: 00: 00.00
alter system checkpoint;系统已更改。
已用时间: 00: 00: 01.04
begin
for i in 1..100000 loop
insert into t2 values(i);
end loop;
end;
/PL/SQL 过程已成功完成。
已用时间: 00: 00: 11.04
commit;提交完成。
已用时间: 00: 00: 00.00
alter system checkpoint;系统已更改。
已用时间: 00: 00: 01.02
在上面的测试中,四次数据插入,最长的时间为12.01秒,最短时间为9.00秒,平均为10.77秒。
可以看出,这两者的差别是相当显著的,这两者参数设置为false时比设置为true竟然快了40%以上。不过这只是个简单的测试,实际情况可能没那么突出,但差异在10%以上是有可能的。
值得注意的是,性能上的差异,主要是由于CPU的消耗造成的,对于CPU资源不足的系统,将这两个参数设置为TRUE无疑会增大CPU的负担,引起性能问题。同时还会引起redo copy latch的持有时间增加和引起这个latch的竞争。
另外,由于不管db_block_checking和db_block_checksum这两个参数的值为何值,SYSTEM表空间都会进行做checking和checksum,除非把隐含参数_db_always_check_system_ts设置为FALSE,当然为了SYSTEM表空间数据安全,不建议将这个隐含参数值设置为FALSE。因此,不要将用户表和索引放到SYSTEM空间中。
在启用一起特定的功能后,SYSTEM表空间中一些表和索引会增长很快。比如启用了审计并且将审计日志存储到数据库中,则AUD$和FGA_LOG$会迅速增长;如果使用高级复制,DEF$_AQCALL表会增加很快,并且如果要复制的数据量比较大,则这个表上的DML是非常多的,在这样的情况会下,会消耗更多的CPU和引起性能降低。如果使用了审计和高级复制,建议将AUD$、FGA_LOG$、DEF$_AQCALL迁移到其他表空间,一方面避免产生大量数据使得SYSTEM表空间过大,另一方面则是避免出现本文提到的性能问题。不过这些表都是特殊的对象,最好在Oracle技术支持指导下进行。DEF$_AQCALL的迁移,请参考metalink doc ID 1037317.6 "Moving the Replication Queue Tables (DEF$) Out of the System Tablespace";AUD$的迁请参考metalink doc ID 72460.1 "Moving AUD$ to Another Tablespace and Adding Triggers to AUD$"
对这两个参数引起的性能差异的深入分析,有兴趣的可参考Oracle hidden costs revealed, Part2 - Using DTrace to find why writes in SYSTEM tablespace are slower than in others
这两个参数不光对DML,对读也是有性能影响的。db_block_checksum参数对读的性能影响和测试,有兴趣的可参考ixora上的文章Note the db_block_checksum parameter setting