Oracle中ASSM模式下,向表中插入数据后被cache在内存的数据块

前言:
其实是一个小问题,不过就是要一点点的进歩,不用在乎进歩多少(给懒惰的自己一个安慰的理由= =)。
遇到问题就是要锲而不舍的探究,也许结果并不怎么重要,不过探究的过程有趣,却又帮助自己了解oracle。
在学习ASSM遇到的小问题,本来想看看插入数据时候,被读入buffer cache的数据块是否如自己想的,结果有差别。
最后,问题的提出在比较后边一点,因为要先构造环境,根据环境提出问题。

操作系统版本:
  1. [oracle@oracle trace]$ uname -a
  2. Linux oracle.example.com 2.6.32-431.el6.x86_64 #1 SMP Sun Nov 10 22:19:54 EST 2013 x86_64 x86_64 x86_64 GNU/Linux
  3. [oracle@oracle trace]$ lsb_release -a
  4. LSB Version:     :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
  5. Distributor ID:  RedHatEnterpriseServer
  6. Description:     Red Hat Enterprise Linux Server release 6.5 (Santiago)
  7. Release:         6.5
  8. Codename:        Santiago

数据库版本:
  1. SYS@proc> select * from v$version where rownum=1;

  2. BANNER
  3. --------------------------------------------------------------------------------
  4. Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

构造环境:
  1. SYS@proc> drop tablespace abc including contents;

  2. Tablespace dropped.

  3. SYS@proc> create tablespace abc datafile '/u01/app/oracle/oradata/proc/abc01.dbf' size 50m reuse uniform size 1m;

  4. Tablespace created.

  5. SYS@proc> create table aa(id int,name varchar(2)) tablespace abc;

  6. Table created.

  7. SYS@proc> select file#,DBABLK,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='AA') and state!=0 order by dbablk;

  8.      FILE#     DBABLK      STATE
  9. ---------- ---------- ----------
  10.          7        128          1
  11.          7        129          1
  12.          7        130          1
  13.          7        131          1

  14. SYS@proc> select extent_id,file_id,block_id,blocks from dba_extents where owner='SYS' and segment_name='AA';

  15.  EXTENT_ID    FILE_ID   BLOCK_ID     BLOCKS
  16. ---------- ---------- ---------- ----------
  17.          0          7        128        128

  18. SYS@proc> select HEADER_FILE,HEADER_BLOCK from dba_segments where owner='SYS' and segment_name='AA';

  19. HEADER_FILE HEADER_BLOCK
  20. ----------- ------------
  21.           7          131    --file7block131是L3块

对L3块做dump操作,以下是部分trace内容:
  1. Extent Control Header
  2.   -----------------------------------------------------------------
  3.   Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 128
  4.                   last map 0x00000000 #maps: 0 offset: 2716
  5.       Highwater:: 0x01c00084 ext#: 0 blk#: 4 ext size: 128
  6.   #blocks in seg. hdr's freelists: 0
  7.   #blocks below: 0
  8.   mapblk 0x00000000 offset: 0
  9.                    Unlocked
  10.   --------------------------------------------------------
  11.   Low HighWater Mark :
  12.       Highwater:: 0x01c00084 ext#: 0 blk#: 4 ext size: 128
  13.   #blocks in seg. hdr's freelists: 0
  14.   #blocks below: 0
  15.   mapblk 0x00000000 offset: 0
  16.   Level 1 BMB for High HWM block: 0x01c00080
  17.   Level 1 BMB for Low HWM block: 0x01c00080
  18.   --------------------------------------------------------
  19.   Segment Type: 1 nl2: 1 blksz: 8192 fbsz: 0
  20.   L2 Array start offset: 0x00001434
  21.   First Level 3 BMB: 0x00000000
  22.   L2 Hint for inserts: 0x01c00082
  23.   Last Level 1 BMB: 0x01c00081
  24.   Last Level II BMB: 0x01c00082
  25.   Last Level III BMB: 0x00000000
  26.      Map Header:: next 0x00000000 #extents: 1 obj#: 89427 flag: 0x10000000
  27.   Inc # 0
  28.   Extent Map
  29.   -----------------------------------------------------------------
  30.    0x01c00080 length: 128

  31.   Auxillary Map
  32.   --------------------------------------------------------
  33.    Extent 0 : L1 dba: 0x01c00080 Data dba: 0x01c00084
  34.   --------------------------------------------------------

  35.    Second Level Bitmap block DBAs
  36.    --------------------------------------------------------
  37.    DBA 1: 0x01c00082

  38. End dump data blocks tsn: 23 file#: 7 minblk 131 maxblk 131
从L3的trace内容得到:
1.L2块是0x01c00082,即7号文件130号块。
2.L1块是0x01c00080,即7号文件128号块(不是准确的)。

可以dumpL2块获得所有的L1块:
  1. Dump of Second Level Bitmap Block
  2.    number: 2 nfree: 2 ffree: 0 pdba: 0x01c00083
  3.    Inc #: 0 Objd: 89427
  4.   opcode:0
  5.  xid:
  6.   L1 Ranges :
  7.   --------------------------------------------------------
  8.    0x01c00080 Free: 5 Inst: 1
  9.    0x01c00081 Free: 5 Inst: 1

  10.   --------------------------------------------------------
  11. End dump data blocks tsn: 23 file#: 7 minblk 130 maxblk 130
从L2的trace内容得到:L1块有7号文件的128和129两个块。

分别dump128和129得到:
1.128中的数据块范围是:长度64,128-191
2.129中的数据块范围是:长度64,192-255
dump过程省略。

环境构造完成,并附上基本说明。
提出问题
按照ASSM下插入数据寻找块的过程(受到高水位线影响),Oracle首先寻找L3号块,根据L3中L2 Hint for inserts(本例为L2 Hint for inserts: 0x01c00082)确定L2号块。然后确定L1号块却是根据PID做HASH随机得到一个N值,在L2中确定了第N号的L1之后,根据PID做HASH再次得到一个随机数M,并将数据插入L1中M号数据块。
根据这个过程,那么如果我向本例的AA表插入一行数据,被读进buffer cache的块就应该是L3(131号),L2(130号),L1(128号,因为高水位线是132号块),和数据块(132号)。

实验过程:
  1. SYS@proc> select file#,DBABLK,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='AA') and state!=0 order by dbablk;

  2. no rows selected

  3. SYS@proc>
  4. SYS@proc> insert into aa values(1,'aa');

  5. 1 row created.

  6. SYS@proc> select file#,DBABLK,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='AA') and state!=0 order by dbablk;

  7.      FILE#     DBABLK      STATE
  8. ---------- ---------- ----------
  9.          7        128          1
  10.          7        129          1
  11.          7        130          1
  12.          7        131          3
  13.          7        131          1
  14.          7        144          1
  15.          7        145          1
  16.          7        146          1
  17.          7        147          1
  18.          7        148          1
  19.          7        149          1

  20.      FILE#     DBABLK      STATE
  21. ---------- ---------- ----------
  22.          7        150          1
  23.          7        151          1
  24.          7        152          1
  25.          7        153          1
  26.          7        154          1
  27.          7        155          1
  28.          7        156          1
  29.          7        157          1
  30.          7        158          1
  31.          7        159          1

  32. 21 rows selected.
看到这个结果很是不解,按照猜想,不应该读入这么多个块。
于是尝试rollback,并清空buffer cache,再次插入是什么情况。
  1. SYS@proc> rollback;

  2. Rollback complete.

  3. SYS@proc> alter system flush buffer_cache;

  4. System altered.

  5. SYS@proc> select file#,DBABLK,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='AA') and state!=0 order by dbablk;

  6. no rows selected

  7. SYS@proc> insert into aa values(1,'aa');

  8. 1 row created.

  9. SYS@proc> select file#,DBABLK,state from x$bh where obj=(select data_object_id from dba_objects where owner='SYS' and object_name='AA') and state!=0 order by dbablk;

  10.      FILE#     DBABLK      STATE
  11. ---------- ---------- ----------
  12.          7        128          1
  13.          7        130          1
  14.          7        131          1
  15.          7        149          1
得到这个结果我之后,尝试再次dump128号块,得到以下结果(dump之前先flush buffer cache):
  1. --------------------------------------------------------
  2.   DBA Ranges :
  3.   --------------------------------------------------------
  4.    0x01c00080 Length: 64 Offset: 0

  5.    0:Metadata 1:Metadata 2:Metadata 3:Metadata
  6.    4:unformatted 5:unformatted 6:unformatted 7:unformatted
  7.    8:unformatted 9:unformatted 10:unformatted 11:unformatted
  8.    12:unformatted 13:unformatted 14:unformatted 15:unformatted
  9.    16:75-100% free 17:75-100% free 18:75-100% free 19:75-100% free
  10.    20:75-100% free 21:75-100% free 22:75-100% free 23:75-100% free
  11.    24:75-100% free 25:75-100% free 26:75-100% free 27:75-100% free
  12.    28:75-100% free 29:75-100% free 30:75-100% free 31:75-100% free
  13.    32:unformatted 33:unformatted 34:unformatted 35:unformatted
  14.    36:unformatted 37:unformatted 38:unformatted 39:unformatted
  15.    40:unformatted 41:unformatted 42:unformatted 43:unformatted
  16.    44:unformatted 45:unformatted 46:unformatted 47:unformatted
  17.    48:unformatted 49:unformatted 50:unformatted 51:unformatted
  18.    52:unformatted 53:unformatted 54:unformatted 55:unformatted
  19.    56:unformatted 57:unformatted 58:unformatted 59:unformatted
  20.    60:unformatted 61:unformatted 62:unformatted 63:unformatted
  21.   --------------------------------------------------------
  22. End dump data blocks tsn: 23 file#: 7 minblk 128 maxblk 128
可以看到块中第16-31状态变成“75-700% free”,那么一开始插入那么多块被读入buffer cache的原因就很清楚了,第16-31刚好对应144-159,而rollback之后重新插入却只有四个块,是因为已经格式化过数据块了。

但是这里却有了另外一个问题,根据原先的提出“如果我向本例的AA表插入一行数据,被读进buffer cache的块就应该是L3(131号),L2(130号),L1(128号,因为高水位线是132号块),和数据块(132号)。”,是的,第二次的4个块是128,130,131和149,而我们猜测的却是128,130,131和132。
我们猜测132是因为插入数据时,高水位线是132号块,但是这里却超过高水位线132去插入149,难道还有这种操作,我觉得Oracle显然不会这样,可能因为是格式化数据块的时候,高水位线也变化了,根据变化规则,猜测高水位线应该变到了192号块。
dump一下L3看看吧。
  1. Extent Control Header
  2.   -----------------------------------------------------------------
  3.   Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 128
  4.                   last map 0x00000000 #maps: 0 offset: 2716
  5.       Highwater:: 0x01c000c0 ext#: 0 blk#: 64 ext size: 128
  6.   #blocks in seg. hdr's freelists: 0
  7.   #blocks below: 60
  8.   mapblk 0x00000000 offset: 0
  9.                    Unlocked
  10.   --------------------------------------------------------
  11.   Low HighWater Mark :
  12.       Highwater:: 0x01c00084 ext#: 0 blk#: 4 ext size: 128
  13.   #blocks in seg. hdr's freelists: 0
  14.   #blocks below: 0
  15.   mapblk 0x00000000 offset: 0
  16.   Level 1 BMB for High HWM block: 0x01c00080
  17.   Level 1 BMB for Low HWM block: 0x01c00080
  18.   --------------------------------------------------------
  19.   Segment Type: 1 nl2: 1 blksz: 8192 fbsz: 0
  20.   L2 Array start offset: 0x00001434
  21.   First Level 3 BMB: 0x00000000
  22.   L2 Hint for inserts: 0x01c00082
  23.   Last Level 1 BMB: 0x01c00081
  24.   Last Level II BMB: 0x01c00082
  25.   Last Level III BMB: 0x00000000
  26.      Map Header:: next 0x00000000 #extents: 1 obj#: 89427 flag: 0x10000000
  27.   Inc # 0
  28.   Extent Map
  29.   -----------------------------------------------------------------
  30.    0x01c00080 length: 128

  31.   Auxillary Map
  32.   --------------------------------------------------------
  33.    Extent 0 : L1 dba: 0x01c00080 Data dba: 0x01c00084
  34.   --------------------------------------------------------

  35.    Second Level Bitmap block DBAs
  36.    --------------------------------------------------------
  37.    DBA 1: 0x01c00082

  38. End dump data blocks tsn: 23 file#: 7 minblk 131 maxblk 131
可以看到Highwater:: 0x01c000c0刚好就是7号文件192号块,确实就符合了,插入时此处固定会读取128,130,131,然后随机选择132-191的数据库插入数据(当然不包括高水位线192块了)。


其他资料:

插入一行数据格式的数据块个数是不固定的,有过5个,16个,32个,64个等。

插入一行数据格式化的数据块数量应该是和区大小以及高水位位置有一定关系吧,总之格式化数据块是按批进行的,具体一批是多少还不清楚。

在L1块中关于数据块的状态有7种格式:Unformat       75-100%       50-75%       25-50%      0-25%   FULL    Metadata

请使用浏览器的分享功能分享到微信等