rdba(转)

 

ROWID的含义与块地址rdba深入分析

Oracle 8以下ROWID组成(也叫受限Rowid)为:FFFF.BBBBBBBB.RRRR,占用6个字节(10bit file#+22bit+16bit),但是,为了扩充的需要,如数据文件的扩充,现在的Rowid改为:OOOOOOFFFBBBBBBRRR,占用10个字节(32bit+10bit rfile#+22bit+16bit)。其中,O是对象ID,F是文件ID,B是块ID,R是行ID。由于rowid的组成从file#变成了rfile#,所以数据文件数的限制也从整个库不能超过1023个变成了每个表空间不能超过1023个数据文件。

 

注意:这里的O,代表的是data_object_id,是与段物理存储位置相关的一个信息,因为一个段对象只可能在一个表空间上,data_object_id能唯一确认ts#,而data_object_id + rfile#就能最终定位到该rowid在那个确定的物理数据文件。

 

如果我们查询一个表的ROWID,就可以获得object的信息,文件信息,块信息与行信息等等,如根据其中块的信息,可以知道该表确切占用了多少个块,每行在哪个块上,哪个数据文件上。

用例子说明一下Rowid的组成:

  1. SQL> select rowid from emp where rownum = 1; 
  2.      AAAAeNAADAAAAWZAAA

分解一下,可以看到

 
 

Data Object number = AAAAeN

File = AAD

Block = AAAAWZ

ROW = AAA

另外,我们需要注意的是,ROWID是64进制的,分布关系如下

 
 

A-Z <==> 0 - 25 (26)

a-z <==> 26 - 51 (26)

0-9 <==> 52 - 61 (10)

+/ <==> 62 - 63 (2)

拿其中的Data Object number= AAAAeN为例子,

N是64进制中的13,位置为0

13 * (64 ^ 0) = 13

E是64进制中的30,位置为1

30 * (64 ^ 1) = 1920

A是64进制中的 0

所以

 
 

A * (64 ^ 2) = 0

A * (64 ^ 3) = 0

A * (64 ^ 4) = 0

A * (64 ^ 5) = 0

则有AAAAeN = 0 + 0 + 0 + 0 + 1920 + 13 = 1933,表示该行存在的对象,对应的对象号为1933。

而且,我们也可以利用oracle提供的包,dbms_rowid来做到这一点:

  1. select dbms_rowid.rowid_object('AAAAeNAADAAAAWZAAA') data_object_id#,
  2.        dbms_rowid.rowid_relative_fno('AAAAeNAADAAAAWZAAA') rfile#,
  3.        dbms_rowid.rowid_block_number('AAAAeNAADAAAAWZAAA') block#,
  4.        dbms_rowid.rowid_row_number('AAAAeNAADAAAAWZAAA') row# from dual;
  5.        DATA_OBJECT_ID#     RFILE#     BLOCK#       ROW#
  6.        --------------- ---------- ---------- ----------
  7.                   1933          3       1433          0

关于更多dbms_rowid的用法,可以参考包的说明或者是oracle手册。

 

如果明白了以上ROWID的含义,那么我们就很容易理解块的地址了rdba了,也就是ROWID中的FFFBBBBBB部分,10bit rfile#+22bit,如我们分析一个块地址:

DBA: 0×2fc0100a

那么,把0×2fc0100a转换成2进制为

 
 

2 f c 0 1 0 0 a

0010 1111 1100 0000 0001 0000 0000 1010

再次转换

0010 1111 11 00 0000 0001 0000 0000 1010

=—————— —————————

数据文件id 块ID

=191(十进制) =4106(十进制)

或者0×2fc0100a=十进制的801116170

  1. SQL> select dbms_utility.data_block_address_file(801116170) "file",
  2.   2         dbms_utility.data_block_address_block(801116170) "block" 
  3.   3         from dual;
  4.       file      block
  5. ---------- ----------
  6.        191       4106

注意,这里得到的191是rfile#,相对文件号,而相对文件号是不能超过1023,所以,如果你想根据这个地址来dump数据文件块的话,最好还是核对一下v$datafile:

select file# from v$datafile where rfile# = 191 and ts# = <:dbfile_in_ts>

  1. SQL> select file# from v$datafile where rfile# = 191 and ts# = 9;
  2.      FILE#
  3. ----------
  4.       1214

这里的9代表该数据文件所在的表空间的编号,你是不是惊奇的发现,这个块地址真正的数据文件编号应当是1214。而不是我们转换得到的191。

不过一般的情况下,数据库的数据文件都没有1023个,所以这个时候的数据文件编号file#与rfile#基本是对应的,这个时候,如果我们要dump这个数据块,就可以采用如下的方式来dump

  1. alter system dump datafile 1214 block 4106;

 

如何从相对文件号和数据块号计算RDBA(相对数据块地址)

RDBA长度是32比特,前10个表示相对文件号,后22个表示数据块号。

假设有一数据块文件号为5,块号为203:

转换:
    fno#: 5 =>0000000101
    bno#: 203 => 0000000000000011001011

连接:
    0000000101 +0000000000000011001011 => 00000001010000000000000011001011

得到 RDBA:
    00000001010000000000000011001011 => (In hex): 14000cb
                               => (In dec): 20971723

当然也可以使用dbms_utility.MAKE_DATA_BLOCK_ADDRESS得到这个地址(前提是数据库还在那里)。

如果是Bigfile表空间的块,那么32个比特全表示块地址了,相对文件号恒等于1024。
 
 

puber晶晶的一篇文章http://space.itpub.net/13095417/viewspace-171150
介绍了ASSM寻找free block的过程其中在转储L3块的时候,在文件中有这样一项
L2 Hint for inserts:  0x010002e2
这是寻找L2块的线索,但是这是一个rdba地址,我们如何从这个块地址中知道file_id和block_id呢?进而进一步转储研究呢?

还得先复习一下rowid的知识:
------------------------------------------
我们都知道rowid表示一行的物理地址,一行唯一确定一个rowid,并且在使用中一般不会改变,除非rowid之后在行的物理位置发生改变的情况下才会发生变化。需要注意的是rowid并不会真正存在于表的data block中,但是他会存在于index当中,用来通过rowid来寻找表中的行数据。
oracle8以前一个rowid占用6个字节大小的存储空间(10bit file#+22bit block#+16bit row#),那么oracle 8以后这个rowid的存储空间扩大到了10个字节(32bit object#+10bit rfile#+22bit block#+16bit row#),所以数据库中数据库文件个数的限制从整个数据库最多只能有的2^10-1个数据文件,变为了每个表空间中可以最多有2^10-1个数据文件。(需要注意的是:local index中存储的rowid是6个字节,而global index中存储的rowid是10个字节)
那么增加的32bit object#这个前缀主要就是用来定位表空间的,同时这个object#其实对应的就是data_object_id,由于一个段对象只能属于一个表空间,同时data_object_id就是标识了一个段的物理存储id.因此object#+rfile#就可以唯一定位当前的rowid是在那个数据文件上了。
我们可以通过dbms_rowid这个包来转换我们的rowid成不同组成部分

dbms_rowid.rowid_object(rowid)---&gt 32bit object#
dbms_rowid.rowid_relative_fno(rowid)---&gt 10bit rfile#
dbms_rowid.rowid_block_number(rowid)---&gt 22bit block#
dbms_rowid.rowid_row_number(rowid)---&gt 16bit row#

那么理解了rowid的组成,我们就很容易的理解rdba的计算了
其实rdba就是rowid中的rfile#+block#

对于0x010002e2这个地址,由于他是一个16进制的数字串,转换为10进制就是16777954

这个时候我们就可以通过dbms_utility这个包来进而分解我们的rdba地址
SQL>select dbms_utility.data_block_address_file(16777954) "file",dbms_utility.data_block_address_block(16777954) "block"
  2  from dual;

      file      block
---------- ----------
         4        738

这样我们在根据这条记录的内容来转储L2块信息:

alter system dump datafile 4 block 738

基本上就是这样。



来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/758322/viewspace-683168/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/758322/viewspace-683168/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值