Oracle在执行全表扫描(Full Table Scan,FTS)、全索引扫描(Index Full Scan)或快速索引全扫描(Index Fast Full Scan)时,为保障性能,尽量一次性读取多个块,这称为Multi Block I/O。每次执行Multi Block I/O,都会等待物理I/O结束,此时等待db file scattered read事件。
但我见过不少朋友在研究db file scattered read等待的时候,总是说模拟不出这个等待事件出来。好,看下面环境:
sys@MAA> select * from v$version;
BANNER
----------------------------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
我用到的脚本:
[oracle@maa3 ~]$ cat showevent.sql
select event, total_waits, time_waited
from v$session_event
where sid=(select sid from v$mystat where rownum=1)
order by 3 desc
/
[oracle@maa3 ~]$ cat GetHparDes.sql
set pagesize 9999
set line 130
col NAME for a20
col VALUE for a20
col DESCRIB for a80
SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc DESCRIB
FROM SYS.x$ksppi x, SYS.x$ksppcv y
WHERE x.inst_id = USERENV ('Instance')
AND y.inst_id = USERENV ('Instance')
AND x.indx = y.indx
AND x.ksppinm LIKE '%&par%'
/
我有一张100万记录的表,目前没有创建任何索引
luocs@MAA> select count(*) from LTB;
COUNT(*)
----------
1000000
数据库采用AMM,memory_target分配了500M
sys@MAA> show parameter memory_target
NAME TYPE VALUE
------------------------------------ ---------------------- ------------------------------
memory_target big integer 500M
我进行了一次FTS扫描,从10046 trace file里只能看到大量direct path read事件,而看不到期待的db file scattered read等待事件
……
WAIT #47878792991760: nam='direct path read' ela= 40 file number=8 first dba=131 block cnt=5 obj#=23315 tim=1356465468282010
WAIT #47878792991760: nam='direct path read' ela= 38 file number=8 first dba=200 block cnt=8 obj#=23315 tim=1356465468282079
WAIT #47878792991760: nam='direct path read' ela= 54 file number=8 first dba=217 block cnt=15 obj#=23315 tim=1356465468282367
……
Oracle 11g,在大表的全表扫描算法上有新的变化,根据表的大小、高速缓存的大小等信息,决定是否绕过SGA直接从磁盘读取数据。而10g则是全部通过高速缓存读取数据。Oracle 11g认为大表全表时使用直接路径读,可能比10g中的数据文件散列读(db file scattered reads)速度更快,效率更高,因此我们看到的大部分为direct path read等待事件。
Oracle 11g提供我们选择权,这个选择权可以通过隐含参数来控制,就是"_serial_direct_read",此参数默认值为auto
sys@MAA> @GetHparDes
Enter value for par: serial_direct_read
old 6: AND x.ksppinm LIKE '%&par%'
new 6: AND x.ksppinm LIKE '%serial_direct_read%'
NAME VALUE DESCRIB
-------------------- -------------------- --------------------------------------------------------------------------------
_serial_direct_read auto enable direct read in serial
该隐含参数是动态参数,我们可以通过alter system set方式修改
- _serial_direct_read = FALSE,禁用direct path read
- _serial_direct_read = TURE,重新启用direct path read
我们可以将其值设置为NEVER,来减少derect path read的等待
sys@MAA> alter system set "_serial_direct_read"=never;
System altered.
查看当前会话的SPID
luocs@MAA> select spid from v$process p, v$session s where p.addr=s.paddr and sid=(select sid from v$mystat where rownum=1);
SPID
------------------------------------------------
26601
通过10046事件查看
sys@MAA> oradebug setospid 26601
Oracle pid: 35, Unix process pid: 26601, image: [email protected] (TNS V1-V3)
sys@MAA> oradebug unlimit
Statement processed.
sys@MAA> oradebug event 10046 trace name context forever,level 12
Statement processed.
执行一个FTS
luocs@MAA> select count(*) from ltb;
COUNT(*)
----------
1000000
sys@MAA> oradebug event 10046 trace name context off
Statement processed.
sys@MAA> oradebug tracefile_name
/u01/app/oracle/diag/rdbms/maa/maa/trace/maa_ora_26601.trc
这下我们能够看到大量db file scattered read了。
[oracle@maa3 ~]$ vi /u01/app/oracle/diag/rdbms/maa/maa/trace/maa_ora_26601.trc…….
…….
WAIT #47878792599648: nam='db file scattered read' ela= 34 file#=8 block#=131 blocks=5 obj#=23315 tim=1356470039698744
WAIT #47878792599648: nam='db file scattered read' ela= 27 file#=8 block#=200 blocks=8 obj#=23315 tim=1356470039699325
WAIT #47878792599648: nam='db file scattered read' ela= 20 file#=8 block#=217 blocks=7 obj#=23315 tim=1356470039699788
WAIT #47878792599648: nam='db file scattered read' ela= 22 file#=8 block#=224 blocks=8 obj#=23315 tim=1356470039700179
WAIT #47878792599648: nam='db file scattered read' ela= 19 file#=8 block#=241 blocks=7 obj#=23315 tim=1356470039700589
…….
event事件里也能看到其内容
luocs@MAA> @showevent
EVENT TOTAL_WAITS TIME_WAITED
----------------------------------------------------------------- ----------- -----------
SQL*Net message from client 24 21760
db file sequential read 103 57
db file scattered read 121 35
db file parallel read 2 2
events in waitclass Other 1 0
SQL*Net message to client 25 0
Disk file operations I/O 5 0
SQL*Net break/reset to client 1 0
KSV master wait 2 0
9 rows selected.
下面我写一个PL/SQL来批量FTS,为效果明显,我定期刷新db cache
declare
c integer;
begin
for i in 1 .. 100 loop
select count(*) into c from ltb;
if mod(i,10)=0 then
execute immediate 'alter system flush buffer_cache';
end if;
end loop;
end;
/
在另一个会话通过v$session_wait观察:
sys@MAA> select SID, EVENT, P1, P2, P3 from V$SESSION_WAIT where event like '%scattered%';
SID EVENT P1 P2 P3
---------- ------------------------------------------------------- ---------- ---------- ----------
37 db file scattered read 9 320 37
sys@MAA> select SID, EVENT, P1, P2, P3 from V$SESSION_WAIT where event like '%scattered%';
SID EVENT P1 P2 P3
---------- ------------------------------------------------------- ---------- ---------- ----------
37 db file scattered read 9 898 37
sys@MAA> select SID, EVENT, P1, P2, P3 from V$SESSION_WAIT where event like '%scattered%';
SID EVENT P1 P2 P3
---------- ------------------------------------------------------- ---------- ---------- ----------
37 db file scattered read 11 8293 27
sys@MAA> select SID, EVENT, P1, P2, P3 from V$SESSION_WAIT where event like '%scattered%';
SID EVENT P1 P2 P3
---------- ------------------------------------------------------- ---------- ---------- ----------
37 db file scattered read 10 935 25
�C OK,轻易看到了db file scattered read等待事件。
下面开始看索引的情况,我添加一个唯一主键
luocs@MAA> alter table ltb add constraint cons_ltb_pk primary key(id);
Table altered.
现在查询会走IFFS
luocs@MAA> set autot trace exp
luocs@MAA> select count(id) from ltb;
Execution Plan
----------------------------------------------------------
Plan hash value: 903694340
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 571 (1)| 00:00:07 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| CONS_LTB_PK | 1000K| 571 (1)| 00:00:07 |
-----------------------------------------------------------------------------
通过下面的PL/SQL,可以观察v$session_wait的事件
declare
c integer;
begin
for i in 1 .. 100 loop
select count(*) into c from ltb;
if mod(i,10)=0 then
execute immediate 'alter system flush buffer_cache';
end if;
end loop;
end;
/
sys@MAA> select SID, EVENT, P1, P2, P3 from V$SESSION_WAIT where event like '%scattered%';
SID EVENT P1 P2 P3
---------- ------------------------------------------------------- ---------- ---------- ----------
37 db file scattered read 11 8524 10
sys@MAA> select SID, EVENT, P1, P2, P3 from V$SESSION_WAIT where event like '%scattered%';
SID EVENT P1 P2 P3
---------- ------------------------------------------------------- ---------- ---------- ----------
37 db file scattered read 9 1026 37
sys@MAA> select SID, EVENT, P1, P2, P3 from V$SESSION_WAIT where event like '%scattered%';
SID EVENT P1 P2 P3
---------- ------------------------------------------------------- ---------- ---------- ----------
37 db file scattered read 11 8524 10
下面通过10046事件查看
trace内容里找到等待事件:
…...
WAIT #47752647311696: nam='db file sequential read' ela= 28 file#=8 block#=170 blocks=1 obj#=23883 tim=1356481191781943
WAIT #47752647311696: nam='db file scattered read' ela= 26 file#=8 block#=171 blocks=5 obj#=23883 tim=1356481191782086
WAIT #47752647311696: nam='db file scattered read' ela= 2733 file#=9 block#=144 blocks=8 obj#=23883 tim=1356481191785276
WAIT #47752647311696: nam='db file scattered read' ela= 2479 file#=10 block#=137 blocks=7 obj#=23883 tim=1356481191788466
WAIT #47752647311696: nam='db file scattered read' ela= 2544 file#=11 block#=8760 blocks=8 obj#=23883 tim=1356481191791597
WAIT #47752647311696: nam='db file scattered read' ela= 31 file#=8 block#=209 blocks=7 obj#=23883 tim=1356481191792242
…...
db file scattered read等待事件一般属于"正常"等待事件,所以除非特殊情况,我们不需要太过在意。
若果列出db file scattered read等待的解决方法,那就如下:
从应用程考虑,需要帅选出主要发生db file scattered read等待的SQL语句,减少不必要的执行FTS或Index Full Scan,务必按照业务需求来修改,不能盲目说哪种效率必须好,要知道读取大量数据时,多数情况下FTS性能更优。
从Oracle内存层考虑,可以使用多重缓冲池,或者提高DB_FILE_MULTIBLOCK_READ_COUNT参数值。
从Oracle段层考虑,使用合理的分区方案
从OS层考虑,提高物理I/O性能
oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html