欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

Oracle的rowid和rdba庖丁解牛

程序员文章站 2022-05-17 11:45:13
...

Oracle 8以下ROWID组成(也叫受限Rowid)为:FFFF.BBBBBBBB.RRRR,占用6个字节(10bit file#+22bit+16bit),但是,为了扩充的需

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# = <:dbfile_in_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-----

Oracle的rowid和rdba庖丁解牛