搞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