assm三级位图可以说是dba的基础技能知识了,这里用测试的方法验证下三级位图的原理。
1.建立实验环境所需要的表
SQL> create tablespace a1 datafile '/oracle/app/oracle/oradata/ora11/a1.dbf' size 20m;
Tablespace created.
SQL> create user a1 identified by a1 default tablespace a1;
User created.
SQL> grant dba to a1;
Grant succeeded.
SQL> connect a1/a1
Connected.
SQL> create table a as select * from dba_tables;
Table created.
实验环境建立完成之后,就需要摸清楚我们的这个段A的位图及数据块分布情况,我们不直接从视图里面查,这里我们考虑需要通过bbed的方式从数据块中获取位图及数据块分布情况。
2.段头块/L3位图块指向了哪些L2位图块
段由哪些区间构成?这个信息我们需要从段头块中获取出来。当你创建一个段后,即使你没有往里面插入任何数据,系统也是会预先分配一些区给你的。所以段头块是那个块,我们可以通过dba_segments查询出来。就算truncate了这个段,我们仍然能够从dba_segments中查询到段头的信息。
SQL> select HEADER_FILE,HEADER_BLOCK from dba_segments where SEGMENT_NAME='A' and owner='A1';
HEADER_FILE HEADER_BLOCK
----------- ------------
5 130
找到了段头块,就可以用bbed挖掘下信息。
BBED> set filename '/oracle/app/oracle/oradata/ora11/a1.dbf'
FILENAME /oracle/app/oracle/oradata/ora11/a1.dbf
BBED> set block 130
BLOCK# 130
BBED> dump /v offset 0 count 20
File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)
Block: 130 Offsets: 0 to 19 Dba:0x00000000
-------------------------------------------------------
23a20000 82004001 d8321400 00000104 l #.@.....
848d0000 l ....
l ....
这里我们可以看到段头块的第一个offset是23。那么我们的段头块指向的L2位图块在offset 5192的位置。这里请记住段头块的标示是23。
BBED> dump /v offset 5192 count 100
File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)
Block: 130 Offsets: 5192 to 5291 Dba:0x00000000
-------------------------------------------------------
81004001 00000000 00000000 00000000 l ..@.............
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 l ....
从这里我们既可以找到我们的L2位图块,81004001,这里只有1个L2块,因为后面都是00000000(空),因为涉及到操作系统字节序的问题,这里需要转换换成01400081。转换后我们可以使用下列查询找到文件号和块号。
SQL> select dbms_utility.data_block_address_file(to_number('01400081','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('01400081','xxxxxxxx')) as blockno from dual;
FILENO BLOCKNO
---------- ----------
5
5 129
3.L2位图块指向了哪些L1位图块
接下来我们可以继续读我们的L2位图块来寻找我们的L1位图块。可以看到L2的第一个offset是21。请记住L2位图块的标示是21。
BBED> set block 129
BLOCK# 129
BBED> dump /v offset 0 count 20
File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)
Block: 129 Offsets: 0 to 19 Dba:0x00000000
-------------------------------------------------------
21a20000 81004001 d4321400 00000604 l !.@.....
48a10000 l H
L2指向L1数据块的位置从offset 116开始。到哪儿结束需要看后面有没有00000000(空)
BBED> dump /v offset 116 count 100
File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)
Block: 129 Offsets: 116 to 215 Dba:0x00000000
-------------------------------------------------------
80004001 01000100 90004001 01000100 l ..@.......@.....
a0004001 01000100 b0004001 01000100 l ........
c0004001 01000100 d0004001 01000100 l ........
e0004001 05000100 00000000 00000000 l ............
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 l ....
从dump出来的地方我们来看,前面是一个地址,后面跟着是01000100,比较规律,大概7组之后就变成00000000(空)了。 跟上面一样因为字节序的问题,这里我们需要将80004001转换成01400080。然后我们通过下列查询得到了区块的位置。而后面的01000100,前面的01则这个L1下面的块全部填满,无空数据块,后面的01则代表这个块是instance 1产生的。而最后的一个05000100,05则代表着这个L1下面还有空块,可以插入。而后面的01我们说过代表着是instance。如果这个系统是个rac的系统,节点2也插入了数据,那么这里就会显示05000200。
SQL> select dbms_utility.data_block_address_file(to_number('01400080','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('01400080','xxxxxxxx')) as blockno from dual
union
select dbms_utility.data_block_address_file(to_number('01400090','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('01400090','xxxxxxxx')) as blockno from dual
union
select dbms_utility.data_block_address_file(to_number('014000a0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000a0','xxxxxxxx')) as blockno from dual
union
select dbms_utility.data_block_address_file(to_number('014000b0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000b0','xxxxxxxx')) as blockno from dual
union
select dbms_utility.data_block_address_file(to_number('014000c0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000c0','xxxxxxxx')) as blockno from dual
union
select dbms_utility.data_block_address_file(to_number('014000d0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000d0','xxxxxxxx')) as blockno from dual
union
select dbms_utility.data_block_address_file(to_number('014000e0','xxxxxxxx')) as fileno,dbms_utility.data_block_address_block(to_number('014000e0','xxxxxxxx')) as blockno from dual;
FILENO BLOCKNO
---------- ----------
5 128
5 144
5 160
5 176
5 192
5 208
5 224
7 rows selected.
通过上述查询,我们找到了7个L1块的信息。
4.L1位图块指向了哪些数据块
前面我们查到了我们的L2块上指向的L1块,并且清楚的知道哪个L1下面是满的,哪个L1下面还有空闲块。我们就从拿最后一个有空闲块的L1位图块进行分析。
BBED> set block 224
BLOCK# 224
BBED> dump /v offset 0 count 10
File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)
Block: 224 Offsets: 0 to 9 Dba:0x00000000
-------------------------------------------------------
20a20000 e0004001 d432 l .@.
<16 bytes per line>
可以看到L1的第一个offset是20。请记住L1位图块的标示是20。
L1指向数据块的位置从offset 204开始。到哪儿结束需要看后面有没有00000000(空)
BBED> dump /v offset 204 count 80
File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)
Block: 224 Offsets: 204 to 283 Dba:0x00000000
-------------------------------------------------------
e0004001 08000000 00000000 e8004001 l ........08000000 08000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
大家可以看到这里的值是e0004001,08000000,00000000,下一组值是e8004001,08000000,08000000,然后面就是00000000(空)。
这两个的意思是告诉我们L1指向数据块的起始位置,比如e0004001,就是文件5,块224,也就是它自己本身。08000000就代表着这个块后面的连续7个块都是的。而e8004001,08000000,08000000,就是文件5,块232,08000000就代表着这个块后面的连续7个块也是的。而最后一个08000000则代表着offset,这里我们可以不用去管它。所以这里我们就能够知道我们的L1块下面具体的数据块有:
224(它本身),225,226,227,228,229,230,231,232,233,234,235,236,237,238,239。来用下列语句查证一下。
SQL> select distinct dbms_rowid.rowid_block_number(rowid) from a order by 1
可以看到223后面直接就是225,直接此处跳空,这是因为我们的224是L1位图块,后面紧跟着我们刚刚说的225,226,227,228,229,230,231,232,233。但是问题是,这里看不到后面的234到239?这是因为234到239还是空闲没有格式化过的块,但是它已经被L1锁定了。那么我们的L1能不能看到这些情况呢?我们可以观察offset 396。
BBED> dump /v offset 396 count 50
File: /oracle/app/oracle/oradata/ora11/a1.dbf (0)
Block: 224 Offsets: 396 to 445 Dba:0x00000000
-------------------------------------------------------
11111111 11000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
0000 l ..
这里可以看到的是11111111,11000000。那么这个代表什么意思呢?如果这个块是full的话,就是1,是unformatted的话就是0,正好和我们前面看到的吻合。