【转载】oracle之rowid详解
本⽂讨论的是关于oracle从8i开始引进object的概念后的rowid,即扩展(extended)的rowid:
的介绍
先对rowid有个感官认识:
SQL>
lectROWIDfromBruce_testwhererownum<2;
ROWID----------------------------AAABnlAAFAAAAAPAAAROWID的格式如下:
数据对象编号⽂件编号块编号⾏编号OOOOOOFFFBBBBBBRRR
我们可以看出,从上⾯的rowid可以得知:AAABnl是数据对象编号AAF是相关⽂件编号AAAAAP是块编号AAA是⾏编号
怎么依据这些编号得到具体的⼗进制的编码值呢,这是经常遇到的问题。这⾥需要明⽩rowid的是基于64位编码的18个字符显⽰(数据对象编号(6)+⽂件编号(3)+块编号(6)+
⾏编号(3)=18位),其中A-Z<==>0-25(26)a-z<==>26-51(26)0-9<==>52-61(10)+/<==>62-63(2)
共64位,明⽩这个后,就可以计算出10进制的编码值,计算公式如下:d*(b^p)其中:b就是基数,这⾥就是64,p就是从右到左,已0开始的位置数⽐如:上⾯的例⼦⽂件号
AAF,具体的计算应该是:5*(64^0)=5;0*(64^1)=0;0*(64^2)=0;⽂件号就是0+0+5=5刚才提到的是rowid的显⽰⽅式:基于64位编码的18个字符显⽰,其实rowid的存储⽅式
是:10个字节即80位存储,其中数据对象编号需要32位,相关⽂件编号需要10位,块编号需要22,位⾏编号需要16位,由此,我们可以得出:32bit的objectnumber,每个最
多有4G个对象10bit的filenumber,每个对象最多有1022个⽂件(2个⽂件预留)22bit的blocknumber,每个⽂件最多有4M个BLOCK16bit的rownumber,每个BLOCK最多有
64K个ROWS
相关的有⽤的sql
最简单的基于rowid的显⽰⽅式得到的响应的64位编码对应值的sql:
lectrowid,substr(rowid,1,6)"OBJECT",substr(rowid,7,3)"FILE",substr(rowid,10,6)"BLOCK",substr(rowid,16,3)"ROW"fromTableName;
OWIDOBJECTFILEBLOCKROW------------------------------------------------------AAABc4AADAAAGLUAAAAAABc4AADAAAGLUAAA
AAABc4AADAAAGLUAABAAABc4AADAAAGLUAABAAABc4AADAAAGLUAACAAABc4AADAAAGLUAACAAABc4AADAAAGLUAADAAABc4
AADAAAGLUAADAAABc4AADAAAGLUAAEAAABc4AADAAAGLUAAE
通过dbms_rowid这个包,可以直接的得到具体的rowid包含的信息:
lectdbms__object(rowid)object_id,dbms__relative_fno(rowid)file_id,dbms__block_number(rowid)block_id,dbms__row_number(rowid)numfrombruce_twhererownum<5;
OBJECT_IDFILE_IDBLOCK_IDNUM----------------------------------------594432532
59443253003
⼀些使⽤ROWID的函数ROWIDTOCHAR(rowid):将ROWID转换成STRINGCHARTOROWID('rowid_string'):将STRING转换成ROWID
另外,就是⾃⼰写的⼀些函数:(下⾯的函数是⽹友eygle提供)
createorreplacefunctionget_rowid
(l_rowidinvarchar2)returnvarchar2isls_my_rowidvarchar2(200);rowid_typenumber;object_numbernumber;relative_fnonumber;block_numbernumber;row_numbernumber;
begindbms__info(l_rowid,rowid_type,object_number,relative_fno,block_number,row_number);ls_my_rowid:='Object#is:'||to_char(object_number)||chr(10)||'Relative_fnois:'||to_char(relative_fno)||chr(10)||
应⽤上⾯的函数如下:SQL>
lectget_rowid(rowid),namefrombruce_t;
GET_ROWID(ROWID)NAME
----------------------------------------------------------------------------------------------------------------Object#is:5944BruceLauRelative_fnois
:3Blocknumberis:25300Rownumberis:0Object#is
:5944MabelTangRelative_fnois:3Blocknumberis:25300Rownumberis
:1
ROWID:ROWID为该表⾏的唯⼀标识,是⼀个伪列,可以⽤在SELECT中,但不可以⽤INSERT,UPDATE来修改该值。注意:ROWID的表指,普通表,clustertable,
partitiontable,subpartitiontable,index,indexpartitionsandsubpartitions(注意:不包含index-organizedtables).每个表Oracle都存在⼀个伪列ROWID,这个伪列可以⽤
SELECT查看,但是不可以⽤INSERT,UPDATE来修改。你也不可以⽤DELETE来删除ROWID列,Oracle使⽤ROWID列来建⽴内部索引。你可以引⽤ROWID的值,但ROWID
并不存放在数据库中,你可以创建⼀个表包含ROWID数据类型,但Oracle不保证该值是合法的rowids。⽤户必须确保该rowid值是真实合法的。UROWID:UROWID(可以称为
通⽤ROWID,逻辑ROWID):表的⾏地址,表指的是index-organizedtables。IOT中物理rowid是可能变化的,另外Oracle要依靠rowid来建⽴表的索引,所以对IOT表来物理rowid
就不⾏了。Oracle以表的主键为基础引⼊UROWID,在物理rowid基础上建⽴了第⼆个索引。每⼀个逻辑rowid使⽤⼀个第⼆索引和⼀个物理推测(IOT中标识块的⾏)。
UROWID⽀持逻辑和物理的rowids,列UROWID类型可以存储各种rowids,从8.1以后的Oracle才有UROWID类型,它也可以⽤来保存以前的ROWID类型数据信息。更新IOT
的主键可能导致ROWID改变,该⾏的UROWID也会改变。
Oracle使⽤rowid数据类型存储⾏地址,rowid可以分成两种,分别适于不同的对像
Physicalrowids:存储ordinarytable,clusteredtable,tablepartitionandsubpartition,indexe,indexpartitionandsubpartition
Logicalrowids:存储IOT的⾏地址
另⼀种rowid类型叫universalrowed(UROWID),⽀持上述physicalrowid和logicalrowed,并且⽀持⾮oracletable,即⽀持所有类型的rowid,但COMPATIBLE必须在8.1或以上.
1.1ROWID伪列
每个表在oracle内部都有⼀个ROWID伪列,它在所有sql中⽆法显⽰,不占存储空间;它⽤于从表中查询⾏的地址或者在where中进⾏参照,⼀个例⼦如下:
SELECTROWID,last_nameFROMemployees;
Oracle内部使⽤保留在ROWID伪列中的值构建索引结构
再次强调⼀次,rowid伪列不存储在数据库中,它不是数据库数据,这是从databa及table的逻辑结构来说的,事实上,在物理结构上,每⾏由⼀个或多个rowpieces组成,每个row
piece的头部包含了这个piece的address,即rowid.从这个意义上来说,rowid还是占了磁盘空间的.
我们在创建表时,可以为列指定为rowid数据类型,但oracle并不保证列中的数据是合法的rowid值,必须由应⽤程序来保证,另外,类型为rowid的列需要6bytes存储数据
1.2,physicalrowids
只在⾏存在,它的物理地址rowid就不会变化,除⾮export/import,根据rowid可以直接定位到block去fetch数据,所以physical兼具有⾼稳定(stability)和⾼性能(performance)的特点.
这⾥要注意⼀点,对于clusteredtable来说,根据它的存储特点,在同⼀个block中的不同table的⾏可能具有同⼀个rowid;⽽nonclusteredtable,每⼀⾏或初始⾏⽚(initialrowpiece)都有
唯⼀的rowid
要注意rowid的地址固定的特点,在⼀个block的某⼀⾏被delete并commit后,它占据的address可以被其它事务新inrt的⾏重⽤.
Physicalrowid可以是下⾯任⼀⼀种格式:
1)Extendedrowid
使⽤表空间相关的数据块地址,8i及以上使⽤这种格式
2)Restrictedrowid
使⽤数据库范围的数据址地址,oracle7或更早前的版本使⽤
1.2.1extenedrowid
扩展⾏地址是64编码的物理地址,编码字符是A-Z,a-z,0-9,+,and/.
由4部分组成OOOOOOFFFBBBBBBRRR(obj#file#block#row#)
OOOOOO-–dataobjectnumber
FFF–-表空间相对的数据⽂件号
BBBBBB–-块号
RRR---⾏号
注意不是16进制表⽰
SQL>
lectrowid,namefromobj$whererownum<=10;
ROWIDNAME
------------------------------------------------
AAAAASAABAAAAB6ABcACCESS$
AAAAASAABAAAC1QAAKAGGXMLIMP
AAAAASAABAAAC1QAALAGGXQIMP
AAAAASAABAAAGiRAAIALERT_QT
AAAAASAABAAAGiRAAhALERT_QUE
AAAAASAABAAAGujAAoALERT_QUE$1
AAAAASAABAAAGujAApALERT_QUE$1
AAAAASAABAAAGiRAAfALERT_QUE_N
AAAAASAABAAAGiRAAeALERT_QUE_R
AAAAASAABAAAGiRAAGALERT_TYPE
我们可以使⽤dbms_rowid从extenedrowid中抽取各部分信息,或者将extenedrowid转换成restrictedrowed,详细的信息参见_rowid的规范
#根据rowid抽块对像编号
SQL>
lectdbms__object('AAAAASAABAAAGiRAAG')obj#fromdual;
OBJ
#----------
18
#根据rowid抽取表空间相对⽂件号
SQL>
lectdbms__relative_fno('AAAAASAABAAAGiRAAG')rfile#fromdual;
RFILE
#----------
1
#根据rowid抽取块号
SQL>
lectdbms__BLOCK_NUMBER('AAAAASAABAAAGiRAAG')block#fromdual;
BLOCK
#----------
26769
#根据rowid抽取⾏号
SQL>
lectdbms__row_number('AAAAASAABAAAGiRAAG')row#fromdual;
ROW
#----------
6
#将extendedrowid转换成为restrictedrowid
SQL>
lectdbms__to_restricted('AAAAASAABAAAGiRAAG',0)restricted_rowidfromdual;
RESTRICTED_ROWID
------------------
00006891.0006.0001
1.2.2restrictedrowid
限制地址⾏号与扩展地址⾏号编码⽅式不⼀样,它在内部使⽤⼆进制⽅式表⽰,当⽤lect查询时,会转换成varchar2/16进制的混合形式,它的组织⽅式如下:
(block#.row#.file#)
注意,这⾥的⽂件号是绝对⽂件号,⽽extendedrowid中是相对⽂件号(相对表空间)
Restrictedrowid中不再有objectnumber,因为从绝对⽂件号可以唯⼀确定数据块
样例可以参考前⾯的00006891.0006.0001
另外请注意,块中的⾏号是从0开始
除了⽤dbms_rowid来抽取rowid的不同部分外,也可以⽤substr
#extendedrowid
SQL>
SELECTROWID,SUBSTR(ROWID,1,6)"OBJECT",SUBSTR(ROWID,7,3)"FIL",SUBSTR(ROWID,10,6)"BLOCK",SUBSTR(ROWID,16,3)"ROW"fromobj$whererownum<=5;
ROWIDOBJECTFILBLOCKROW------------------------------------------------------AAAAASAABAAAAB6AAaAAAAASAABAAAAB6AAa
AAAAASAABAAAAB6AAuAAAAASAABAAAAB6AAuAAAAASAABAAAAB6AAFAAAAASAABAAAAB6AAFAAAAASAABAAAAB6AAvAAAAAS
AABAAAAB6AAvAAAAASAABAAAAB6AAZAAAAASAABAAAAB6AAZ
#restrictedrowidSQL>
SELECTROWID,SUBSTR(ROWID,15,4)"FILE",SUBSTR(ROWID,1,8)"BLOCK",SUBSTR(ROWID,10,4)"ROW"fromobj$whererownum<=5;
ROWIDFILEBLOCKROW--------------------------------------------------AAAAASAABAAAAB6AAa6AAaAAAAASAAAAAAAAAAASAABAAAAB6AAu
6AAuAAAAASAAAAAAAAAAASAABAAAAB6AAF6AAFAAAAASAAAAAAAAAAASAABAAAAB6AAv6AAvAAAAASAAAAAA
AAAAASAABAAAAB6AAZ6AAZAAAAASAAAAAA
请注意extentedrowid与restrictedrowid的编码⽅式不⼀样,⼤家不能拿两种不同编码⽅式的作⽐较,⽐如AAAAASAABAAAAB6AAa这⾏的File#在两种⽅式下是有不同的值,表
⽰不同的意义,没有可⽐性.
下⾯的语句可以查看表的数据分布在⼏个⽂件中
SQL>
SELECTCOUNT(DISTINCT(SUBSTR(ROWID,7,3)))"FILES"FROMBOSSSTATSDATA;
FILES----------17
#下⾯验证bossstatsdata的数据确实分布在17个⽂件中
SQL>
lectcount(file_name)fromdba_data_fileswhereTABLESPACE_NAME=(lectTABLESPACE_NAMEfromur_tableswheretable_name='BOSSSTATSDATA');
COUNT(FILE_NAME)----------------17
总结Rowid的使⽤场景
1)构建索引结构,每个key都有⼀个rowid指向相应的表⾏
2)rowid是访问表⾏的最快的⽅法
3)rowid可⽤于观察表数据是怎样组织的
4)rowid是表⾏的唯⼀标识符
在任何DML中使⽤rowid时,应该注意确保相关的⾏不会改变物理地址(不会被export/import,delete)
1.3logicalrowids⽤于表达IOT⾏地址的Logicalrowid存储在索引的叶⼦节点中,会随着索引entry的inrt在块内或块间移动,所以,它不是基于物理地址⽽是基于primarykey的
标识符,所以取名叫logcialrowid使⽤logicalrowids来构建IOT的condaryindexes由于在实际的应⽤中很少会使⽤到IOT这种对像,关于logicalrowid更详细的描述可以参见
<
1.4⾮oracletable中的rowid在⾮oracle中,不同的系统有不同的rowid格式,并且,不能使⽤前述标准的rowid到varchar2/16进制的转换⽅法,所以,在这种情况下,应⽤程序可以使
⽤rowid数据类型,不过要使⽤⾮标准的转换⽅法(最长256bytes的16进制)⾮oracle系统中的rowid也能存储在UROWID数据类型中
作者“jukyoc”
本文发布于:2022-11-14 00:49:22,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/88/14399.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |