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的信息,文件信息,块信息与行信息等等,如根据其中块的信息,可以知道该表确切占用了多少个块,每行在哪个块上,哪个数据文件上。
我们在select数据时候,在不指定排序字段时, oracle是按rowid升序取数据的。如
sql> select t.id,rowid from skate.tab2 t;
id rowid
---------- ------------------
1067511 aaao1laaeaaahkkaaa
1067513 aaao1laaeaaahkkaab
1067515 aaao1laaeaaahkkaac
1067517 aaao1laaeaaahkkaad
1067519 aaao1laaeaaahkkaae
1067523 aaao1laaeaaahkkaag
1067525 aaao1laaeaaahkkaah
1067527 aaao1laaeaaahkkaai
8 rows selected
sql>
可以从上面的显示数据看到,是按rowid降序排列。我们拿rowid “aaao1laaeaaahkkaaa”来说明
data object number =aaao1l
file id =aae
block id =aaahkk
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= aaao1l为例子,
l是64进制中的37,位置为0
37 * (64 ^ 0) = 37
1是64进制中的53,位置为1
53 * (64 ^ 1) = 3392
o是64进制中的 14,位置为2
14*(64^2)=57344
a是64进制中的 0
所以
a * (64 ^ 3) = 0
a * (64 ^ 4) = 0
a * (64 ^ 5) = 0
则有aaao1l= 0 + 0 + 0 + 57344+ 3392 + 37 = 60773,表示该行存在的对象,对应的对象号为60773。
手工算还是比较麻烦的,oracle为此提供相应的函数dbms_rowid来实现
sql> select dbms_rowid.rowid_object('aaao1laaeaaahkkaaa') data_object_id#,
2 dbms_rowid.rowid_relative_fno('aaao1laaeaaahkkaaa') rfile#,
3 dbms_rowid.rowid_block_number('aaao1laaeaaahkkaaa') block#,
4 dbms_rowid.rowid_row_number('aaao1laaeaaahkkaaa') row# from dual;
data_object_id# rfile# block# row#
--------------- ---------- ---------- ----------
60773 4 29348 0
可以通过包的说明或者oracle官方手册了解更多,例如:
sql> desc dbms_rowid
element type
---------------------- ---------
rowid_type_restricted constant
rowid_type_extended constant
rowid_is_valid constant
rowid_is_invalid constant
rowid_object_undefined constant
rowid_convert_internal constant
rowid_convert_external constant
rowid_invalid exception
rowid_bad_block exception
rowid_create function
rowid_info procedure
rowid_type function
rowid_object function
rowid_relative_fno function
rowid_block_number function
rowid_row_number function
rowid_to_absolute_fno function
rowid_to_extended function
rowid_to_restricted function
rowid_verify function
sql> desc dbms_rowid.rowid_info
parameter type mode default?
------------- -------- ---- --------
rowid_in rowid in
rowid_type number out
object_number number out
relative_fno number out
block_number number out
row_number number out
ts_type_in varchar2 in y
如果明白了以上rowid的含义,那么就很容易理解块的地址rdba了,也就是rowid中的fffbbbbbb部分,10bit rfile#+22bit,如我们分析一个块地址:
rdba: 0x010072a4
把0x010072a4转化为10进制16806564
sql> select dbms_utility.data_block_address_file(16806564) file,
2 dbms_utility.data_block_address_block(16806564) block
3 from dual;
file block
---------- ----------
4 29348
sql>
现在通过块的dba知道了file和block,那怎样确认我们推到的正确呢? 这个块地址是dump文件的内容,我们可以去dump文件核对下
start dump data blocks tsn: 4 file#: 4 minblk 29348 maxblk 29348
buffer tsn: 4 rdba: 0x010072a4 (4/29348)
scn: 0x0000.00e66a1e seq: 0x02 flg: 0x06 tail: 0x6a1e0602
frmt: 0x02 chkval: 0x4590 type: 0x06=trans data
hex dump of block: st=0, typ_found=1
结果我们推导的和dump的内容是一样的,不过这里得到的4是rfile#,相对文件号,而相对文件号是不能超过1023,所以,如果你想根据这个地址来dump数据文件块的话,最好还是核对一下v$datafile:
select file# from v$datafile where rfile# = 4 and ts# =
表空间的ts#可以通过如下sql得到:
select ta.tablespace_name, da.ts#
from dba_tablespaces ta, dba_data_files df, v$datafile da
where ta.tablespace_name = df.tablespace_name
and da.name = df.file_name
例如:
sql> select file# from v$datafile where rfile# = 4 and ts# = 4;
file#
----------
4
sql>
如果数据文件数大于1023个,这里file# 就不是4了,应该是个绝对文件号了,这就是file#和rfile#的区别。如果dump数据块,要用绝对文件号的,例如:
alter system dump datafile 4 block 29348;
也可以通过dba_segments,如
sql> select header_file,header_block from dba_segments where owner='skate' and segment_name='tab2';
header_file header_block
----------- ------------
4 29347
这里段头占有一个block,后面存储的就是数据,所以存储数据的块,应该是29348
-----end-----
