日期:2014-05-16  浏览次数:20399 次

oracle伪列 rowid和rownum

整理ROWID一

一,什么是伪列RowID?
1,首先是一种数据类型,唯一标识一条记录物理位置的一个id,基于64位编码的18个字符显示。
2,未存储在表中,可以从表中查询,但不支持插入,更新,删除它们的值。

二,RowID的用途
1,在开发中使用频率应该是挺多的,特别在一些update语句中使用更加频繁。所以oracle ERP中大部份的视图都会加入rowid这个字段。
?? 在一些cursor定义时也少不了加入rowid。但往往我们在开发过程中,由于连接的表很多,再加上程序的复制,有时忽略了rowid对应的是那一个表中rowid,所以有时过程出错,
?? 往往发上很多时间去查错,最后查出来既然是update时带的rowid并非此表的rowid,所以在发现很多次的错误时,重视rowid起来了,开发中一定要注意rowid的匹配
2,能以做快的方式访问表中的一行。
3,能显示表的行是如何存储的。
4,作为表中唯一标识。

三,RowID的组成
rowid确定了每条记录是在Oracle中的哪一个数据对象,数据文件、块、行上。
ROWID 的格式如下:
?? 数据对象编号??????? 文件编号??????? 块编号??????????? 行编号
?? OOOOOO???????????? FFF??????????????? BBBBBB??? RRR
??
?? 由 data_object_id# + rfile# + block# + row#?? 组成,占用10个bytes的空间,
??? 32bit的 data_object_id#,
??? 10 bit 的 rfile#,??
??? 22bit 的 block#,
??? 16 bit 的 row#.??
?? 所以每个表空间不能超过1023个 数据文件。

四,RowID的应用
1,查找和删除重复记录
?? 当试图对库表中的某一列或几列创建唯一索引时,
?? 系统提示 ORA-01452 :不能创建唯一索引,发现重复记录。
??
??? /*conn scott/tiger
??? Create table empa as select * from emp;
??? 插入重复记录
??? insert into empa select * from emp where empno = 7369;
??? insert into empa select * from emp where empno = 7839;
??? insert into empa select * from emp where empno = 7934;
??? */
?? 查找重复记录的几种方法:
??? 查找大量重复记录
??? select empno from empa group by empno having count(*) >1;
??? Select * From empa Where ROWID Not In(Select Min(ROWID) From empa Group By empno);
??? 查找少量重复记录
??? select * from empa a where rowid<>(select max(rowid) from empa where empno=a.empno );

?? 删除重复记录的几种方法:
??? (1).适用于有大量重复记录的情况(列上建有索引的时候,用以下语句效率会很高):
??? Delete empa Where empno In (Select empno From empa Group By empno Having Count(*) > 1)
??? And ROWID Not In (Select Min(ROWID) From empa Group By empno Having Count(*) > 1);
???
??? Delete empa Where ROWID Not In(Select Min(ROWID) From empa Group By empno);
???
??? (2).适用于有少量重复记录的情况(注意,对于有大量重复记录的情况,用以下语句效率会很低):
??? Delete empa a where rowid<>(select max(rowid) from empa where empno=a.empno );

?

整理ROWID二??

?????? 搞oracle都会经常碰到rowid,本文是笔者根据网上各位的文章,加上自己学习中的体会,总结而成。
一.rowid简介

??????? rowid就是唯一标志记录物理位置的一个id,在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个 数据文件。
??????? 说了rowid的组成,那么我们再来看看rowid在索引里面占用的字节数又是什么样子的。在oracle 8以前索引中存储的rowid占用字节数也是6bytes,在oracle8之后,虽然oracle使用了extend rowid,但是在普通索引里面依然存储了bytes的rowid,只有在global index中存储的是10bytes的extend rowid,而extend rowid也是global index出现的一个必要条件,下面我们会解释原因。

??????? 为什么golbal index需要把data_object_id#也包含在index rowid entry中呢?如果不包含会这么样?首先我们需要知道index的rowid entry的存在是为了能根据它找到表的这条记录存在哪个具体的物理位置,我们需要知道它在哪个数据文件,在哪个block,在那一行,普通的索引 oracle根据rfile#,block#,row#就可以知道了,但是partition table可以分布在多个表空间,也就是可以分布在多个数据文件,当我们建立local index时,index rowid entry并不包含data_object_id#,因为oracle可以知道这个index对应的是哪一个table分区,并可以得到table分区的 ts#(tablespace号),那么oracle根据ts#和rfile#就可以找到具体的数据文件。但是如果换成是golbal index,如果不包含data_object_id#,那么我们并不能知道这个索引对应着哪个表分区,也自然不能知道它的rfile#和file#的转 换关系,所以它将找不到所对应的记录。包含data_object_id#后,oracle可以根据data_object_id#实现rfile#和 file#的转换然后找到记录对应的物理位置。需要注意的是要理解以上概念我们还是需要了解file#和rfile#的区别。

二.比较file#和rfile#

oracle数据文件为什么存在file#和rfile#?