db_file_multiblock_read_count
2013-01-23 10:01
330 查看
一、参数说明:
初始化参数db_file_multiblock_read_count是用来约束Oracle进行多数据块读取时的行为,所谓多数据块读取,就是Oracle在一次I/O时,可以读取多个数据块,从而用最小的I/O完成数据的读取。
db_file_multiblock_read_count的设置要受OS最大IO能力影响,也就是说,如果你系统的硬件IO能力有限,即使设置再大的db_file_multiblock_read_count也是没用的。
理论上,最大db_file_multiblock_read_count和系统IO能力应该有如下关系:
Max(db_file_multiblock_read_count) = MaxOsIOsize/db_block_size
当然这个Max(db_file_multiblock_read_count)还要受Oracle的限制。
在这里引用一下Oracle 11g r2的Reference中关于db_file_multiblock_read_count的介绍:
二、实验说明:
在这里引用一下谭大师的《让Oracle跑得更快2》中的一个例子:
在这里要说明一下SQL> alter table jack minimize records_per_block;该语句的作用:
三、设置db_file_multiblock_read_count为不同的值,观察SQL的性能变化,写出几种类型的SQL会从这个参数中受益
四、总结
对于OLTP数据库,每次用户读取的记录数非常少,这个值可以考虑设置小一点;而对于OLAP数据库,因为查询的量非常大,索引可以考虑设置大一些,但是需要注意多数据块读取只发生在以下两种情况下:
FTS(FULL TABLE SCAN)
INDEX_FFS(INDEX FAST FULL SCAN)
关于这个参数,在Oracle 10G r2及以后的版本里,Oracle不建议修改它的默认值,当设置这个参数为默认值时,Oracle会通过收集SQL的I/O情况,来动态设置这个参数的值;如果手工修改了它的默认值,Oracle将使用这个新的值。
初始化参数db_file_multiblock_read_count是用来约束Oracle进行多数据块读取时的行为,所谓多数据块读取,就是Oracle在一次I/O时,可以读取多个数据块,从而用最小的I/O完成数据的读取。
db_file_multiblock_read_count的设置要受OS最大IO能力影响,也就是说,如果你系统的硬件IO能力有限,即使设置再大的db_file_multiblock_read_count也是没用的。
理论上,最大db_file_multiblock_read_count和系统IO能力应该有如下关系:
Max(db_file_multiblock_read_count) = MaxOsIOsize/db_block_size
当然这个Max(db_file_multiblock_read_count)还要受Oracle的限制。
在这里引用一下Oracle 11g r2的Reference中关于db_file_multiblock_read_count的介绍:
二、实验说明:
在这里引用一下谭大师的《让Oracle跑得更快2》中的一个例子:
----创建一张表jack并插入一下数据---- 1 SQL> create table jack(x int,y int); Table created. SQL> insert into jack values(1,1); 1 row created. SQL> insert into jack values(2,1); 1 row created. ----将表jack中的每个数据块存放在记录数收缩到最小,以便于记录分布在尽可能多的数据块上---- 13 SQL> alter table jack minimize records_per_block; Table altered. ----再次插入一下数据,并做一下数据分析---- 17 SQL> insert into jack select rownum+2,1 from all_objects where rownum<=254; 254 rows created. SQL> create index jack_ind on jack(x); Index created. SQL> exec dbms_stats.gather_table_stats(user,'jack'); PL/SQL procedure successfully completed. ----下面的查询说明jack表占用的数据块数为128个。 29 SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)) from jack; COUNT(DISTINCTDBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)) --------------------------------------------------- 128 ----清楚缓存,并将数据块间隔着读入内存中---- 35 SQL> alter system flush buffer_cache; System altered. SQL> alter session set db_file_multiblock_read_count = 64; Session altered. SQL> declare 2 l_y number; 3 begin 4 for i in 1..64 loop 5 select y into l_y from jack where x = i*4; 6 end loop; 7 end; 8 / PL/SQL procedure successfully completed. ----查看一下trace文件的路径---- 54 SQL> @showtrace trace_file_name -------------------------------------------------------------------------------- /u01/app/oracle/diag/rdbms/yft/yft/trace/yft_ora_4556.trc [oracle@yft ~]$ cat showtrace.sql SELECT d.VALUE || '/' || LOWER (RTRIM(i.INSTANCE,CHR(0))) || '_ora_' || p.spid || '.trc' as "trace_file_name" FROM (SELECT p.spid FROM v$mystat m,v$session s,v$process p WHERE m.statistic# = 1 AND s.SID = m.SID AND p.addr = s.paddr) p, (SELECT t.INSTANCE FROM v$thread t,v$parameter v WHERE v.NAME = 'thread' AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i, (SELECT VALUE FROM v$parameter WHERE NAME = 'user_dump_dest') d; ----打开10046事件,并进行一次全表扫描---- 78 SQL> alter session set events '10046 trace name context forever,level 12'; Session altered. SQL> set autotrace traceonly statistics; SQL> select * from jack; 256 rows selected. Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 199 consistent gets 123 physical reads 0 redo size 4829 bytes sent via SQL*Net to client 606 bytes received via SQL*Net from client 19 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 256 rows processed SQL> alter session set events '10046 trace name context off'; Session altered. ---查看10046事件中的信息---- 105 [oracle@yft ~]$ cat /u01/app/oracle/diag/rdbms/yft/yft/trace/yft_ora_4556.trc WAIT #14: nam='db file sequential read' ela= 41 file#=6 block#=157 blocks=1 obj#=75062 tim=1358893053963775 WAIT #14: nam='db file sequential read' ela= 83 file#=6 block#=159 blocks=1 obj#=75062 tim=1358893053963907 WAIT #14: nam='db file sequential read' ela= 104 file#=6 block#=161 blocks=1 obj#=75062 tim=1358893053964108 WAIT #14: nam='db file scattered read' ela= 124 file#=6 block#=163 blocks=2 obj#=75062 tim=1358893053964318 FETCH #14:c=1000,e=698,p=5,cr=8,cu=0,mis=0,r=15,dep=0,og=1,plh=949574992,tim=1358893053964360 WAIT #14: nam='SQL*Net message from client' ela= 129 driver id=1650815232 #bytes=1 p3=0 obj#=75062 tim=1358893053964536 WAIT #14: nam='SQL*Net message to client' ela= 3 driver id=1650815232 #bytes=1 p3=0 obj#=75062 tim=1358893053964625 WAIT #14: nam='db file sequential read' ela= 92 file#=6 block#=166 blocks=1 obj#=75062 tim=1358893053964774 WAIT #14: nam='db file sequential read' ela= 91 file#=6 block#=168 blocks=1 obj#=75062 tim=1358893053964930 FETCH #14:c=0,e=393,p=2,cr=8,cu=0,mis=0,r=15,dep=0,og=1,plh=949574992,tim=1358893053964999 WAIT #14: nam='SQL*Net message from client' ela= 129 driver id=1650815232 #bytes=1 p3=0 obj#=75062 tim=1358893053965174 WAIT #14: nam='db file scattered read' ela= 221 file#=6 block#=171 blocks=2 obj#=75062 tim=1358893053965485 WAIT #14: nam='SQL*Net message to client' ela= 3 driver id=1650815232 #bytes=1 p3=0 obj#=75062 tim=1358893053965536 WAIT #14: nam='db file sequential read' ela= 64 file#=6 block#=174 blocks=1 obj#=75062 tim=1358893053965695 WAIT #14: nam='db file sequential read' ela= 85 file#=6 block#=178 blocks=1 obj#=75062 tim=1358893053965849 这个例子展示了Oracle多个数据块读取的工作机制,当内存中已经有了某个数据块时,Oracle将不再从磁盘中读取它。这里使用一个循环来通过索引块访问的方式(每次读取一个数据块), 将间隔的数据块读入到内存中,这样即使db_file_multiblock_read_count设置为64时,执行jack表的全表扫描时,由于已经没有连续的数据块可供读取了,所以Oracle每次也只能将一个数据块读取到内存。 在等待时间中每一个WAIT#中blocks=1说明每一次I/O读取的数据块都为1,而且数据块的序号正好间隔为1,说明它们之间的那个数据块已经读取到内存中了。
在这里要说明一下SQL> alter table jack minimize records_per_block;该语句的作用:
SQL> create table echo (x int,y int); Table created. SQL> insert into echo values(1,1); 1 row created. SQL> insert into echo values(2,1); 1 row created. SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)) from echo; COUNT(DISTINCTDBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)) --------------------------------------------------- 1 SQL> insert into echo select rownum+2,1 from all_objects where rownum<=254; 254 rows created. SQL> select count(distinct dbms_rowid.rowid_block_number(rowid)) from echo; COUNT(DISTINCTDBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)) --------------------------------------------------- 在这里很明显可以看到没有使用alter table jack minimize records_per_block语句时,echo表占用的数据块数为1. 1
三、设置db_file_multiblock_read_count为不同的值,观察SQL的性能变化,写出几种类型的SQL会从这个参数中受益
----创建一张echo表---- 1 SQL> create table echo as select * from dba_objects; Table created. SQL> set autotrace trace exp; ----将参数设置成16,此时没有索引,只能进行全表扫描---- 6 SQL> alter session set db_file_multiblock_read_count=16; Session altered. SQL> select * from echo; Execution Plan ---------------------------------------------------------- Plan hash value: 642657756 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 63977 | 12M| 234 (1)| 00:00:03 | | 1 | TABLE ACCESS FULL| ECHO | 63977 | 12M| 234 (1)| 00:00:03 | -------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) SQL> alter session set db_file_multiblock_read_count=60; Session altered. SQL> select * from echo; Execution Plan ---------------------------------------------------------- Plan hash value: 642657756 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 63977 | 12M| 194 (1)| 00:00:03 | | 1 | TABLE ACCESS FULL| ECHO | 63977 | 12M| 194 (1)| 00:00:03 | -------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) SQL> alter session set db_file_multiblock_read_count=128; Session altered. SQL> select * from echo; Execution Plan ---------------------------------------------------------- Plan hash value: 642657756 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 63977 | 12M| 186 (1)| 00:00:03 | | 1 | TABLE ACCESS FULL| ECHO | 63977 | 12M| 186 (1)| 00:00:03 | -------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) -----当参数设定为16,60,128时,CBO计算出的FTS成本分别是234,194,186,很显然当参数的值越高CBO更倾向于全表扫描。 68 ----给表创建一个主键---- 69 SQL> alter table echo add constraint pk_echo primary key (object_id); Table altered. SQL> alter session set db_file_multiblock_read_count=16; Session altered. SQL> select count(*) from echo; Execution Plan ---------------------------------------------------------- Plan hash value: 1123611804 ------------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 38 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | INDEX FAST FULL SCAN| PK_ECHO | 63977 | 38 (0)| 00:00:01 | ------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) SQL> alter session set db_file_multiblock_read_count=60; Session altered. SQL> select count(*) from echo; Execution Plan ---------------------------------------------------------- Plan hash value: 1123611804 ------------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 31 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | INDEX FAST FULL SCAN| PK_ECHO | 63977 | 31 (0)| 00:00:01 | ------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) SQL> alter session set db_file_multiblock_read_count=128; Session altered. SQL> select count(*) from echo; Execution Plan ---------------------------------------------------------- Plan hash value: 1123611804 ------------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 30 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | | | | 2 | INDEX FAST FULL SCAN| PK_ECHO | 63977 | 30 (0)| 00:00:01 | ------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) ----进行INDEX_FFS查询时,参数的值越大CBO计算的成本越低 138 ----执行INDEX RANGE SCAN查询---- 139 SQL> alter session set db_file_multiblock_read_count=16; Session altered. SQL> select * from echo where object_id<1000; Execution Plan ---------------------------------------------------------- Plan hash value: 3487819792 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 942 | 190K| 29 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| ECHO | 942 | 190K| 29 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | PK_ECHO | 942 | | 4 (0)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"<1000) Note ----- - dynamic sampling used for this statement (level=2) SQL> alter session set db_file_multiblock_read_count=60; Session altered. SQL> select * from echo where object_id<1000; Execution Plan ---------------------------------------------------------- Plan hash value: 3487819792 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 942 | 190K| 29 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| ECHO | 942 | 190K| 29 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | PK_ECHO | 942 | | 4 (0)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"<1000) Note ----- - dynamic sampling used for this statement (level=2) SQL> alter session set db_file_multiblock_read_count=128; Session altered. SQL> select * from echo where object_id<1000; Execution Plan ---------------------------------------------------------- Plan hash value: 3487819792 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 942 | 190K| 29 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| ECHO | 942 | 190K| 29 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | PK_ECHO | 942 | | 4 (0)| 00:00:01 | --------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"<1000) Note ----- - dynamic sampling used for this statement (level=2) ----当参数的值改变时,CBO计算的成本没有发生变化 219 ----执行INDEX FULL SCAN查询---- 220 SQL> alter session set db_file_multiblock_read_count=16; Session altered. SQL> select object_id from echo order by object_id; Execution Plan ---------------------------------------------------------- Plan hash value: 1544245908 ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 63977 | 812K| 165 (0)| 00:00:02 | | 1 | INDEX FULL SCAN | PK_ECHO | 63977 | 812K| 165 (0)| 00:00:02 | ---------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) SQL> alter session set db_file_multiblock_read_count=60; Session altered. SQL> select object_id from echo order by object_id; Execution Plan ---------------------------------------------------------- Plan hash value: 1544245908 ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 63977 | 812K| 165 (0)| 00:00:02 | | 1 | INDEX FULL SCAN | PK_ECHO | 63977 | 812K| 165 (0)| 00:00:02 | ---------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) SQL> alter session set db_file_multiblock_read_count=128; Session altered. SQL> select object_id from echo order by object_id; Execution Plan ---------------------------------------------------------- Plan hash value: 1544245908 ---------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 63977 | 812K| 165 (0)| 00:00:02 | | 1 | INDEX FULL SCAN | PK_ECHO | 63977 | 812K| 165 (0)| 00:00:02 | ---------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) ----当参数的值改变时,CBO计算的成本没有发生变化 总结:在这里只列举是4种查询方式,可以看出当参数的值越大时,FTS和INDEX_FFS的成本就会越低,执行计划就越向这边倾斜。
四、总结
对于OLTP数据库,每次用户读取的记录数非常少,这个值可以考虑设置小一点;而对于OLAP数据库,因为查询的量非常大,索引可以考虑设置大一些,但是需要注意多数据块读取只发生在以下两种情况下:
FTS(FULL TABLE SCAN)
INDEX_FFS(INDEX FAST FULL SCAN)
关于这个参数,在Oracle 10G r2及以后的版本里,Oracle不建议修改它的默认值,当设置这个参数为默认值时,Oracle会通过收集SQL的I/O情况,来动态设置这个参数的值;如果手工修改了它的默认值,Oracle将使用这个新的值。
相关文章推荐
- db_file_multiblock_read_count 的自动调整
- Oracle 10R2 研究--db_file_multiblock_read_count对成本的影响
- stripe /block size/db_file_multiblock_read_count
- db_file_multiblock_read_count参数设置取值测试
- 考量参数DB_FILE_MULTIBLOCK_READ_COUNT的脚本
- 测量一次I/0最多能读多少块 【验证db_file_multiblock_read_count的值】
- oracle中的db_file_multiblock_read_count参数
- 使用 db_file_multiblock_read_count测试Oracle在不同系统中的IO能力
- 共享SQL区、私有SQL区与游标 (提到参数DB_FILE_MULTIBLOCK_READ_COUNT)
- db_file_multiblock_read_count 的自动调整
- oracle DB_FILE_MULTIBLOCK_READ_COUNT参数和区间尺寸的设置
- How is Parameter DB_FILE_MULTIBLOCK_READ_COUNT Calculated? (Doc ID 1398860.1)
- 关于参数db_file_multiblock_read_count与_db_file_optimizer_read_count
- db_file_multiblock_read_count 的自动调整
- db_file_multiblock_read_count and Oracle IO size
- 通过案例学调优之--Oracle参数(db_file_multiblock_read_count)
- db_file_multiblock_read_count 的自动调整
- 实验讲解DB_FILE_MULTIBLOCK_READ_COUNT对物理读和IO次数的影响
- db_file_multiblock_read_count 的自动调整
- 关于db_file_multiblock_read_count的物理读