关于ROWID是否重复的问题

来源:互联网 发布:晕3d的人是天才知乎 编辑:程序博客网 时间:2024/06/05 14:08

作者:iamlaosong

在进行邮件成本计算时发现有的邮件号码重复(非正常现象,重复收寄),虽然很少,但因此就不能按邮件号码更新数据,只能按ROWID更新数据,那么ROWID是如何定义的,是否会重复呢?

In Oracle, when you insert a row, a rowid is assigned to it and that row will forever have that rowid. The flashback table process will perform a DELETE against EMP and reinsert the rows, hence assigning them a new rowid
--from Expert Oracle Database Architecture    Thomas Kyte

从这一段话中可以肯定的是在一个表中ROWID肯定是不会重复的,那么不同的表会不会重复呢?这和ROWID的构成有关,在oracle 8版本以前,rowid由file# block# row#组成,占用6个bytes的空间,10 bit 的 file# ,22bit 的 block# ,16 bit 的 row#。从oracle 8开始rowid变成了extend rowid,由data_object_id# rfile# block# row#组成,占用10个bytes的空间, 32bit的 data_object_id#,10 bit 的 rfile#,22bit 的 block#,16 bit 的 row#.由于rowid的组成从file#变成了rfile#,所以数据文件数的限制也从整个库不能超过1023个变成了每个表空间不能超过1023个 数据文件。

 
select rowid from dual;
AAAAB0AABAAAAOhAAA


rowid结构如下:
对象号    文件号   块号   行号
XXXXXX    XXX     XXXXXX XXX
因此,
AAAAB0 对象号
AAB    文件号
AAAAOh 块号
AAA    行号

从这个构成可以看出,ROWID是不会重复的。


附:Oracle的rowid



Oracle中的ROWID是数据的物理地址。一个ROWID包含关于文件、块和该块中的行的一行信息。ROWID还包含其它数据,如相关文件数和OBJECT_ID。


  ROWID可以分为物理rowid和逻辑rowid两种。普通的堆表中的rowid是物理rowid,索引组织表(IOT)的rowid是逻辑rowid。oracle提供了一种urowid的数据类型,同时支持物理和逻辑rowid。本文主要关注物理rowid。


  物理rowid又分为扩展rowid(extended rowid)和限制rowid(restricted rowid)两种格式。限制rowid主要是oracle7以前的rowid格式,现在已经不再使用,保留该类型只是为了兼容性。所以本文的提到物理rowid一般是指扩展rowid格式。


  1.Rowid的显示形式


  我们从rowid伪列里select出来的rowid是基于base64编码,一共有18位,分为4部分:


  OOOOOOFFFBBBBBBRRR


  其中:


  OOOOOO: 六位表示data object id,根据object id可以确定segment。关于data object id和object id的区别,请参考http://www.orawh.com/index.php/archives/62


  FFF: 三位表示相对文件号。根据该相对文件号可以得到绝对文件号,从而确定datafile。关于相对文件号和绝对文件号,请参考http://blog.itpub.net/post/330/22749


  BBBBBB:六位表示data block number。这里的data block number是相对于datafile的编号,而不是相对于tablespace的编号。


  RRR:三位表示row number。


  Oracle提供了dbm_rowid来进行rowid的一些转换计算。


  SQL> create table test(id int,name varchar2(30));


  Table created.


  SQL> insert into test values(1,'a');


  1 row created.


  SQL> commit;


  Commit complete.


  SQL> select rowid from test;


  ROWID


  ------------------


  AAAGbEAAHAAAAB8AAA


  SQL> select dbms_rowid.rowid_object(rowid) obj#,


  2 dbms_rowid.rowid_relative_fno(rowid) rfile#,


  3 dbms_rowid.rowid_block_number(rowid) block#,


  4 dbms_rowid.rowid_row_number(rowid) row#,


  5 dbms_rowid.rowid_to_absolute_fno(rowid,'SYS','TEST') file#


  6 from test;


  OBJ# RFILE# BLOCK# ROW# FILE#


  ----------- ------------ ------------- ---------- ----------


  26308 7 124 0 7


  2. 如何从rowid计算得到obj#,rfile#,block#,row#


  rowid是base64编码的,用A~Z a~z 0~9 + /共64个字符表示。A表示0,B表示1,……,a表示26,……,0表示52,……,+表示62,/表示63可以将其看做一个64进制的数。


  所以,


  obj#=AAAGbE=6*64^2+27*64+4=26308


  rfile#=AAH=7


  block#=AAAAB8=64+60=124


  row#=AAA=0


  3. 如何从obj#,rfile#,block#,row#计算得到rowid


  实际上就是将十进制数转化成64进制数,当然,从二进制转化的规则比较简单点。


  将二进制数从右到左,6个bit一组,然后将这6个bit组转成10进制数,就是A~Z a~z 0~9 + /这64个字符的位置(从0开始),替换成base64的字符即可。


  obj#=26308=110 011011 000100=6 27 4=G b E,补足成6位base64编码,左边填0,也就是A,结果为AAAGbE


  rfile#=7=111=7=H,补足成3位,得到AAH


  block#=124=1 111100=1 60=B 8,补足成6位,得到AAAAB8


  row#=0,3位AAA


  合起来就是AAAGbEAAHAAAAB8AAA


  4. Rowid的内部存储格式


  虽然我们从rowid伪列中select出来的rowid是以base64字符显示的,但在oracie内部存储的时候还是以原值的二进制表示的。一个扩展rowid采用10个byte来存储,共80bit,其中obj#32bit,rfile#10bit,block#22bit,row#16bit。所以相对文件号不能超过1023,也就是一个表空间的数据文件不能超过1023个(不存在文件号为0的文件),一个datafile只能有2^22=4M个block,,一个block中不能超过2^16=64K行数据。而一个数据库内不能有超过2^32=4G个object。


  SQL> select dump(rowid,16) from test;


  DUMP(ROWID,16)


  --------------------------------------------


  Typ=69 Len=10: 0,0,66,c4,1,c0,0,7c,0,0


  00000000 00000000 01100110 11000100 00000001 11000000 00000000 01111100 00000000 00000000


  最右边16bit为row#=00000000 00000000=0


  接下来22bit为block#=000000 00000000 01111100=124


  接下来10bit为rfile#=00000001 11=7


  接下来32bit为obj#=00000000 00000000 01100110 11000100=26308


  5. Index中存储的rowid


  a. 普通B-tree索引


  SQL> create index ix_test on test(id);


  Index created.


  SQL> select file_id,block_id from dba_extents where segment_name='IX_TEST' and owner=user;

0 0
原创粉丝点击