谈谈Oracle direct path read和direct path write

顾名思义,Oracle 进行direct path read和direct path write操作时,将会绕过buffer_cache,直接将数据读至PGA中。Oracle官方文档也似乎这么说。
但事实果真是这样吗?
接下来分2部分测试,首先测试direct path read,我们知道Oracle并行读时将会产生进行direct path read

SQL> alter system flush buffer_cache;

System altered.

SQL> select /*+ parallel(a 10)*/ * from zhoultest a;

835328 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1476512502

--------------------------------------------------------------------------------
-------------------------------

| Id  | Operation            | Name      | Rows  | Bytes | Cost (%CPU)| Time
|    TQ  |IN-OUT| PQ Distrib |

--------------------------------------------------------------------------------
-------------------------------

|   0 | SELECT STATEMENT     |           |   832K|    62M|   405   (2)| 00:00:05
|        |      |            |

|   1 |  PX COORDINATOR      |           |       |       |            |
|        |      |            |

|   2 |   PX SEND QC (RANDOM)| :TQ10000  |   832K|    62M|   405   (2)| 00:00:05
|  Q1,00 | P->S | QC (RAND)  |

|   3 |    PX BLOCK ITERATOR |           |   832K|    62M|   405   (2)| 00:00:05
|  Q1,00 | PCWC |            |

|   4 |     TABLE ACCESS FULL| ZHOULTEST |   832K|    62M|   405   (2)| 00:00:05
|  Q1,00 | PCWP |            |

--------------------------------------------------------------------------------
-------------------------------
可以看到buffer_cache中只有segment head
SQL> select a.FILE#,a.BLOCK#,b.EXTENT_ID,b.BLOCK_ID,b.blocks,a.DIRTY from v$bh a, dba_extents b where a.file#=b.file_id and a.block# between b.block_id and b.block_id+b.blocks-1
and owner='ZHOUL' and SEGMENT_NAME='ZHOULTEST' and a.status<>'free';
  2 
     FILE#     BLOCK#  EXTENT_ID   BLOCK_ID     BLOCKS D
---------- ---------- ---------- ---------- ---------- -
         7       5131          0       5129          8 N
        
        
SQL> select header_file,header_block from dba_segments where owner='ZHOUL' and SEGMENT_NAME='ZHOULTEST';

HEADER_FILE HEADER_BLOCK
----------- ------------
          7         5131
进一步dump segment head
SQL>  alter system  dump datafile 7 block 5131;

System altered.
可以看到segment head中有HighWater Mark和Extent Map,而Oracle全表扫描时,正是通过Extent Map定位数据块,扫描至高水位以下位置。需要注意的是当表格extent很多时,
不足以放在同一个block中时,就会出现多个区位图块(小表的区位图块和segment head是同一个数据块,如本例),这时就需要一个指针指向下一个区位图块。
用Map Header:: next 0x00000000可以看出,本例中下一个区位图块为空,即只有一个区位图块。
  Extent Control Header
  -----------------------------------------------------------------
  Extent Header:: spare1: 0      spare2: 0      #extents: 118    #blocks: 32896
                  last map  0x00000000  #maps: 0      offset: 2716 
      Highwater::  0x01c0e609  ext#: 117    blk#: 1024   ext size: 1024 
  #blocks in seg. hdr's freelists: 0    
  #blocks below: 32896
  mapblk  0x00000000  offset: 117  
                   Unlocked
  --------------------------------------------------------
  Low HighWater Mark :
      Highwater::  0x01c0e609  ext#: 117    blk#: 1024   ext size: 1024 
  #blocks in seg. hdr's freelists: 0    
  #blocks below: 32896
  mapblk  0x00000000  offset: 117  
  Level 1 BMB for High HWM block: 0x01c0e20c
  Level 1 BMB for Low HWM block: 0x01c0e20c
  --------------------------------------------------------
  Segment Type: 1 nl2: 1      blksz: 8192   fbsz: 0     
  L2 Array start offset:  0x00001434
  First Level 3 BMB:  0x00000000
  L2 Hint for inserts:  0x01c0140a
  Last Level 1 BMB:  0x01c0e20c
  Last Level II BMB:  0x01c0140a
  Last Level III BMB:  0x00000000
     Map Header:: next  0x00000000  #extents: 118  obj#: 72659  flag: 0x10000000
  Inc # 0
  Extent Map
  -----------------------------------------------------------------
   0x01c01409  length: 8    
   0x01c01411  length: 8    
   0x01c01419  length: 8    
   0x01c01421  length: 8 
。。。
通过以上测试我们可以推断出,Oracle在进行并行表格扫描时,需要将表格头和区位图块载入buffer_cache中,通过读取表格头的高水位标记位
和区位图块的区信息,从而定位表格数据块在数据文件中的位置,进而读取数据。
在测试中我们还同时发现了另外两个现象:
(1)Oracel扫描dba_extents(最终对x$ktfbue表格扫描)时,其实就是去读取区位图块的区信息,通过以下测试可以说明这一点。
通过bbed物理修改位图块信息
BBED> modify 0x0a
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y
File: /oradata/mcstar/zhoul01.dbf (0)
Block: 5131             Offsets:  284 to  795           Dba:0x00000000
------------------------------------------------------------------------
0a000000 1114c001 08000000 1914c001 08000000 2114c001 08000000 2914c001
再次查询dba_extents视图,可以观察到数据发生了变化
SQL> select EXTENT_ID,FILE_ID,BLOCK_ID,BLOCKS from dba_extents where SEGMENT_NAME='ZHOULTEST' and OWNER='ZHOUL' order by 1;

EXTENT_ID    FILE_ID   BLOCK_ID     BLOCKS
---------- ---------- ---------- ----------
         0          7       5129         10

(2)Oracle在并行扫描时,将会进行表格级别的checkpoint。
Oracle使用direct path read进行并行查询,即直接从数据文件读取数据至PGA,如果有数据存在于buffer_cache时,势必会影响数据的一致性。所以在在并行扫描时,将会进行表格级别的checkpoint。
以下测试证明了这一点。
首先改变一些数据块
SQL> update  zhoultest set name=lower(name) where rownum<10000;

9999 rows updated.

SQL> commit;

Commit complete.

SQL> select count(*) from v$bh a, dba_extents b where a.file#=b.file_id and a.block# between b.block_id and b.block_id+b.blocks-1
  2  and owner='ZHOUL' and SEGMENT_NAME='ZHOULTEST' and a.status<>'free' and a.dirty='Y';

  COUNT(*)
----------
       116
发起一个并行查询
select /*+ parallel(a 10)*/ * from zhoultest a where rownum<0;
再次查询,可以看到dirty数据块已经从buffer_cache中刷往数据文件中。
SQL> /

  COUNT(*)
----------
         0  
进一步dump buffer_cache中,我们注意到了objq,正是通过这个objq,Oracle加快了在buffer_cache中搜索对象的速度,同理ckptq的存在加快了增量checkpoint的内存搜索效率,
fileq的存在加快了表空间checkpoint的内存搜索效率。
SQL> ALTER SESSION SET EVENTS 'immediate trace name buffers level 2';

Session altered.


BH (0x213f5030) file#: 7 rdba: 0x01c0390c (7/14604) class: 1 ba: 0x2128e000
  set: 6 blksize: 8192 bsi: 0 set-flg: 0 pwbcnt: 0
  dbwrid: 0 obj: 76226 objn: 76226 tsn: 8 afn: 7
  hash: [20fedda0,2a693b68] lru: [22fefd88,213f23b8]
  obj-flags: object_ckpt_list
  ckptq: [22fed090,2a6e3260] fileq: [2a6e32ec,2a6e32ec] objq: [2603ca30,2603ca30]
  st: XCURRENT md: NULL tch: 1
  flags: buffer_dirty gotten_in_current_mode redo_since_read
  LRBA: [0x9331.ede6.0] HSCN: [0xa00.e7f7af9] HSUB: [1]
  buffer tsn: 8 rdba: 0x01c0390c (7/14604)
  scn: 0x0a00.0e7f7af9 seq: 0x02 flg: 0x02 tail: 0x7af90602
  frmt: 0x02 chkval: 0x0000 type: 0x06=trans data

需要注意的是,在Oracle 9i中,并没有objq存在
BH (0x0x53fc77ac) file#: 9 rdba: 0x02410873 (9/67699) class 1 ba: 0x0x5360a000
  set: 6 dbwrid: 0 obj: 44558 objn: 44558
  hash: [83519fa8,83519fa8] lru: [53fc767c,53fc796c]
  LRU flags: moved_to_tail
  ckptq: [NULL] fileq: [NULL]
  st: XCURRENT md: NULL rsop: 0x(nil) tch: 0
  flags: only_sequential_access
  LRBA: [0x0.0.0] HSCN: [0xffff.ffffffff] HSUB: [255] RRBA: [0x0.0.0]
  buffer tsn: 9 rdba: 0x02410873 (9/67699)
  scn: 0x0a00.06200be8 seq: 0x01 flg: 0x04 tail: 0x0be80601
  frmt: 0x02 chkval: 0x4d10 type: 0x06=trans data
我们知道drop table时,也会进行表格级别ckpt,当drop table时,需要在buffer_cache中搜寻和这张表格相关的数据块,如果在高并发Oracle9i环境下,极易引起latch争用,
如lacth:cache buffer chain等。


我们知道在insert时,加hint:/*+ append*/将会执行direct path write,即Oracle绕过buffer_cache,直接写往数据文件。是不是Oracle所有的
数据块都绕过buffer_cache都写往数据文件呢?
接下来继续测试direct path write。
为避免干扰,我们从sys.t1读取内容插往zhoultest表格
SQL> explain plan for insert /*+ append*/ into zhoultest  select * from sys.t1;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1069440229

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | INSERT STATEMENT   |           | 51050 |    63M|   143   (4)| 00:00:02 |
|   1 |  LOAD AS SELECT    | ZHOULTEST |       |       |            |          |
|   2 |   TABLE ACCESS FULL| T1        | 51050 |    63M|   143   (4)| 00:00:02 |
--------------------------------------------------------------------------------

9 rows selected.

SQL> alter system flush buffer_cache;

System altered.

SQL> insert /*+ append*/ into zhoultest  select * from sys.t1;

420896 rows created.

SQL> commit;

Commit complete.

我们看到在buffer_cache中除了segment head还出现了其他数据块。
SQL> select a.FILE#,a.BLOCK#,b.EXTENT_ID,b.BLOCK_ID,b.blocks,a.DIRTY from v$bh a, dba_extents b where a.file#=b.file_id and a.block# between b.block_id and b.block_id+b.blocks-1
and owner='ZHOUL' and SEGMENT_NAME='ZHOULTEST' and a.status<>'free';
  2 
     FILE#     BLOCK#  EXTENT_ID   BLOCK_ID     BLOCKS D
---------- ---------- ---------- ---------- ---------- -
         7       5131          0       5129          8 Y
         7       5130          0       5129          8 Y
         7      24844        101      24841       1024 Y
         7      29962        102      29961       1024 Y
         7      29964        102      29961       1024 Y
         7      29961        102      29961       1024 Y
         7      29963        102      29961       1024 Y
         7      30986        103      30985       1024 Y
         7      30988        103      30985       1024 Y
         7      30985        103      30985       1024 Y
         7      30987        103      30985       1024 Y

     FILE#     BLOCK#  EXTENT_ID   BLOCK_ID     BLOCKS D
---------- ---------- ---------- ---------- ---------- -
         7      32010        104      32009       1024 Y
         7      32012        104      32009       1024 Y
         7      32009        104      32009       1024 Y
         7      32011        104      32009       1024 Y
         7      33036        105      33033       1024 Y
         7      33033        105      33033       1024 Y
         7      33035        105      33033       1024 Y
         7      33034        105      33033       1024 Y
         7      34057        106      34057       1024 Y
         7      34059        106      34057       1024 Y
         7      34058        106      34057       1024 Y

     FILE#     BLOCK#  EXTENT_ID   BLOCK_ID     BLOCKS D
---------- ---------- ---------- ---------- ---------- -
         7      34060        106      34057       1024 Y

23 rows selected.
进一步dump数据块,可以看出是2级位图块
Dump of Second Level Bitmap Block
   number: 230     nfree: 21      ffree: 138    pdba:     0x01c0140b
   Inc #: 0 Objd: 72659
  opcode:0
xid:
  L1 Ranges :
  --------------------------------------------------------
   0x01c01409  Free: 1 Inst: 1
   0x01c01419  Free: 1 Inst: 1
   0x01c01429  Free: 1 Inst: 1
   0x01c01439  Free: 1 Inst: 1
   0x01c01449  Free: 1 Inst: 1
。。。
继续dump其他数据块,看出是1级位图块

SQL> alter system dump datafile 7 block 34060;

System altered.

Dump of First Level Bitmap Block
--------------------------------
   nbits : 4 nranges: 1         parent dba:  0x01c0140a   poffset: 185  
   unformatted: 97      total: 256       first useful block: 0     
   owning instance : 1
   instance ownership changed at
   Last successful Search
   Freeness Status:  nf1 0      nf2 0      nf3 0      nf4 0     

   Extent Map Block Offset: 4294967295
   First free datablock : 159   
   Bitmap block lock opcode 0
   Locker xid:     :  0x0000.000.00000000
   Inc #: 0 Objd: 72659
  HWM Flag: HWM Set
      Highwater::  0x01c088a8  ext#: 106    blk#: 927    ext size: 1024 
  #blocks in seg. hdr's freelists: 0    
  #blocks below: 21535
  mapblk  0x00000000  offset: 106  
。。。

通过以上测试我们可以得出以上推论,在进行direct path write时,由于要改变数据块内容,Oracle需要将反映数据块位置状态的L3,L2,L1,SEGMENT_HEAD读至buffer_cache中。
需要注意的是当进行direct path write时,Oracle会将segment的low hwm至high hwm未格式化的block进行格式化操作,即low hwm=high hwm,然后在high hwm之后插数据
直接路径插入之前
   Extent Control Header
  -----------------------------------------------------------------
  Extent Header:: spare1: 0      spare2: 0      #extents: 119    #blocks: 33920
                  last map  0x00000000  #maps: 0      offset: 2716 
      Highwater::  0x01c0f309  ext#: 118    blk#: 1024   ext size: 1024 
  #blocks in seg. hdr's freelists: 0    
  #blocks below: 33916
  mapblk  0x00000000  offset: 118  
                   Unlocked
  --------------------------------------------------------
  Low HighWater Mark :
      Highwater::  0x01c0ef19  ext#: 118    blk#: 16     ext size: 1024 
  #blocks in seg. hdr's freelists: 0    
  #blocks below: 32908
  mapblk  0x00000000  offset: 118  
  Level 1 BMB for High HWM block: 0x01c0ef0c
  Level 1 BMB for Low HWM block: 0x01c0ef09
仅直接路径插入一行数据
SQL> insert /*+ append*/ into zhoultest  select * from sys.t1 where rownum<2;

1 row created.

SQL> commit;

Commit complete.

再次查看segment head,可以看到high Highwater mask= Low HighWater Mark
Extent Control Header
  -----------------------------------------------------------------
  Extent Header:: spare1: 0      spare2: 0      #extents: 120    #blocks: 34944
                  last map  0x00000000  #maps: 0      offset: 2716 
      Highwater::  0x01c0f40e  ext#: 119    blk#: 5      ext size: 1024 
  #blocks in seg. hdr's freelists: 0    
  #blocks below: 33925
  mapblk  0x00000000  offset: 119  
      Disk Lock:: Locked by xid:  0x002a.021.00000822
  --------------------------------------------------------
  Low HighWater Mark :
      Highwater::  0x01c0f40e  ext#: 119    blk#: 5      ext size: 1024 
  #blocks in seg. hdr's freelists: 0    
  #blocks below: 33925
  mapblk  0x00000000  offset: 119  
  Level 1 BMB for High HWM block: 0x01c0f409
  Level 1 BMB for Low HWM block: 0x01c0f409

你可能感兴趣的:(oracle,sql,cache,ext,Access)