解析Oracle rowid系列一

搞Oracle的人,都知道表里有一个叫做rowid的伪列,也知道可以通过rowid来快速定位表里的记录,至少通过oracle的索引来快速查找表里的数据就是通过rowid来定位的。可是,我们真的对rowid很了解吗?至少,我之前存在了一些误区,甚至有点儿荒谬!在此,对rowid作一个全面解析,同大家分享,以飨网友。

1 Oracle rowid格式:

Oracle rowid format

rowid

OOOOOO

FFF

BBBBBB

RRR

说明

数据对象号

相对文件号

数据块号

行号

上述表格是Oracle 9i及以上版本数据库中的rowid格式:6位对象号+3位相对文件号+6位数据块号+3位行号,是一个18位的64进制值。这个18位的64进制值在数据库内却是以10个bytes合计80个bit的二进制数存放的,和我们直接看到的结果有所区别。这里的64进制和10进制的对应编码如下表:

64进制-10进制转换表

64进制编码

A

B

Z

a

b

z

0

1

9

+

/

10进制值

0

1

25

26

27

51

52

53

61

62

63

2 那么这个18位的64进制值又是如何同80位的二进制数对应的呢?

其中,6位的对象号在数据库中是用32位二进制来存放的,也就意味着一个oracle数据库中最多可以有232个对象,即4G个对象;3位的相对文件号在数据库中是用10位二进制来存放的,也就意味着一个表空间中最多可以容纳210=1024去掉全0和全1个数据文件,即1022个数据文件;6位的数据块号用22位二进制来存放的,也就意味着一个数据文件最多可以包含222=4M个数据块;3位的行号在数据库中是用16位二进制来存放的,也就意味着一个数据块上最多可以容纳216=65536行记录。

3 我们已经对rowid有了基本认识,我们又该如何获取rowid呢?见下例

SQL> show user;
USER is "HR"
SQL> select employee_id,last_name,rowid from employees where employee_id=100;

EMPLOYEE_ID LAST_NAME                 ROWID
----------- ------------------------- ------------------
100 King                      AAAR5pAAFAAAADPAAA

SQL>

我们可以在查询列表中,把rowid伪列当做普通的字段来查询。上例中,AAAR5p就是HR.employees在数据库中的对象号,AAF表示相对文件号,AAAADP则表示数据块编号,最后的3个AAA则表示行号。当然,我们完全可以根据上述的转换表,将这些64进制值直接转成对应的10进制值。分别就是HR.employees表在数据库内的对象号是73321,而该表在数据库内部是存放在第5号文件(AAF=0*642+0*641+5*640=5)上的,employee_id=100的记录则是放在第5号文件的第207个数据块上的;最后的AAA表示该记录是位于第5号文件上的第207个数据块上的第1条记录。

4 除了上述方法,我们还可以通过数据库提供给我们的工具包来获取该信息:

SQL> select rowid,
2  dbms_rowid.rowid_object(rowid) object_id,
3  dbms_rowid.rowid_relative_fno(rowid)  file_id,
4  dbms_rowid.rowid_block_number(rowid)  block_id ,
5  dbms_rowid.rowid_row_number(rowid)   num ,
6  rowidtochar(rowid) from employees where employee_id=100
7  ;

ROWID               OBJECT_ID    FILE_ID   BLOCK_ID        NUM ROWIDTOCHAR(ROWID)
------------------ ---------- ---------- ---------- ---------- ------------------
AAAR5pAAFAAAADPAAA      73321          5        207          0 AAAR5pAAFAAAADPAAA

SQL>

很显然,我们通过调用系统的dbms_rowid包,获得的rowid信息同我们手工将64进制转成10进制得到的结果完全一致!

这是探讨Oracle rowid系列之一,后续将有系列二探讨Cluster table rowid、系列三探讨Bigfile tablespace rowid,敬请关注。

评论 (7)

  • gtlions| 2011年11月19日

    请教了,这段~~~那么这个18位的64进制值又是如何同80位的二进制数对应的呢?其中,6位的对象号在数据库中是用32位二进制来存放的,也就意味着一个oracle数据库中最多可以有232个对象,即4G个对象;3位的相对文件号在数据库中是用10位二进制来存放的,也就意味着一个表空间中最多可以容纳210=1024去掉全0和全1个数据文件,即1022个数据文件;6位的数据块号用22位二进制来存放的,也就意味着一个数据文件最多可以包含222=4M个数据块;3位的行号在数据库中是用16位二进制来存放的,也就意味着一个数据块上最多可以容纳216=65536行记录。~~~
    其中的比如计算对象个数和计算文件个数的2^32和2^10中的:
    32与6位对象号的6
    10与3位相对文件号的3
    怎么关联计算的?

    • 你好世界| 2013年10月9日

      @gtlions
      【32与6位对象号的6】
      6位对象号,每位都是一个64,也就是每一位都是一个2^6。
      所以6位对象号,就是(2^6)^6

  • asher| 2011年11月19日

    您好,gtlions,谢谢您的阅读与回复。
    您的意思是为什么64进制的6位的对象号要用32位二进制来存储,3位的对象号为什么要用10位的二进制来表示是吗?
    我能给出的解释是,这个是oracle规定死的,6位的对象号就是要用32位来表示。我猜测,或许这是Oracle数据库内部的某种算法已经事先规定死的。

  • Rix Chan| 2011年11月19日

    重温一下了。rowid主要作用的什么啊?

  • gtlions| 2011年11月20日

    好吧,因为我实在没办法关联起来

  • David| 2011年12月30日

    一个表空间最多可以有1023个数据文件,相对文件号为1-1023

  • 发表评论

    邮箱地址不会被公开。 必填项已用*标注