ROWID是数据的详细地址,通过rowid,oracle可以快速的定位某行具体的数据的位置。

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的显示形式

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

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

4.Rowid的内部存储格式

5.Index中存储的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;

FILE_ID BLOCK_ID
---------- ----------
7 129

---由于是assm表空间,去掉3个block的头
SQL> alter system dump datafile 1 block 132;

System altered.

得到trace文件内容如下(省略无关内容):
row#0[8024] flag: -----, lock: 0
col 0; len 2; (2): c1 02 ---索引键数据ID=1
col 1; len 6; (6): 01 c0 00 7c 00 00 ---对应的rowid记录
----- end of leaf block dump -----
End dump data blocks tsn: 7 file#: 7 minblk 132 maxblk 132

普通索引中保存的rowid是不包括obj#的,但是分区表的global index是包括obj#的,这是因为分区表包括多个segment,每个segment可能在不同的datafile中,根据表的obj#就无法确定该索引键对应的rowid(rfile#确定不了)。

01 c0 00 7c 00 00 转化为二进制 000000001 11000000 00000000 01111100 00000000 00000000

右边8bit row#=0

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

接下来10bit rfile#=000000001 11=7

b.唯一索引

SQL> drop index ix_test;

Index dropped.

SQL> create unique 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;

FILE_ID BLOCK_ID
---------- ----------
7 129

SQL> alter system dump datafile 1 block 132;

System altered.

得到trace文件内容如下:

row#0[8025] flag: -----, lock: 0, data:(6): 01 c0 00 7c 00 00 ---对应的rowid记录
col 0; len 2; (2): c1 02 ---索引键数据ID=1
----- end of leaf block dump -----
End dump data blocks tsn: 7 file#: 7 minblk 132 maxblk 132

得到rowid为 01 c0 00 7c 00 00,具体的转换计算和前面的一样,就不重复了。

Base64编码说明
  Base64编码要求把3个8位字节(3*8=24)转化为4个6位的字节(4*6=24),之后在6位的前面补两个0,形成8位一个字节的形式。 如果剩下的字符不足3个字节,则用0填充,输出字符使用'=',因此编码后输出的文本末尾可能会出现1或2个'='。

  为了保证所输出的编码位可读字符,Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64,这也是Base64名称的由来。

Base64编码表

码值 字符   码值 字符   码值 字符   码值 字符
0 A 16 Q 32 g 48 w
1 B 17 R 33 h 49 x
2 C 18 S 34 i 50 y
3 D 19 T 35 j 51 z
4 E 20 U 36 k 52 0
5 F 21 V 37 l 53 1
6 G 22 W 38 m 54 2
7 H 23 X 39 n 55 3
8 I 24 Y 40 o 56 4
9 J 25 Z 41 p 57 5
10 K 26 a 42 q 58 6
11 L 27 b 43 r 59 7
12 M 28 c 44 s 60 8
13 N 29 d 45 t 61 9
14 O 30 e 46 u 62 +
15 P 31 f 47 v 63 /

原文链接:http://hi.baidu.com/wwynhm/item/1a376fbc6063b7d084dd79a7
关于《关于base64编码的原理及实现

Oracle的rowid的更多相关文章

  1. 【转载】oracle之rowid详解

    原文URL:http://www.2cto.com/database/201109/104961.html 本文讨论的是关于oracle从8i开始引进object的概念后的rowid,即扩展(exte ...

  2. 【转】oracle中rowid的用法 (全面)

    ROWID是数据的详细地址,通过rowid,oracle可以快速的定位某行具体的数据的位置. ROWID可以分为物理rowid和逻辑rowid两种.普通的堆表中的rowid是物理rowid,索引组织表 ...

  3. 关于oracle的rowid

    oracle数据库中表的每一行(元组)均有一个rowid,它是数据的详细地址,通过rowid,oracle可以快速的定位某行具体的数据的位置. ROWID可以分为物理rowid和逻辑rowid两种.普 ...

  4. oracle 的rowid和rownum

    rowid就是唯一标志记录物理位置的一个id,对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行 ...

  5. 讨论oracle在rowid和rownum

    [ 概要 ] 刚刚接触oracle的同学可能经常会被rowid和rownum这两个词弄混, 弄清楚这两个家伙对于我们写sql会有非常大的帮助, 以下偶就抛砖引玉, 简单地谈谈他们之间的差别吧. [ 比 ...

  6. Oracle数据库RowId

    RowId是什么? RowId是根据每一行数据的物理信息地址编码而成的一个位列,利用RowId可以快速定位到某一行. Oracle数据库编辑数据必须查出RowId,可以根据如下语句查询: select ...

  7. Oracle中ROWID详解

    oracle数据库的表中的每一行数据都有一个唯一的标识符,或者称为rowid,在oracle内部通常就是使用它来访问数据的.rowid需要 10个字节的存储空间,并用18个字符来显示.该值表明了该行在 ...

  8. Oracle的rowid结构解析

    SQL> select rowid,deptno from dept; ROWID                  DEPTNO ------------------ ---------- A ...

  9. Oracle使用rowid删除重复记录

    /**如何删除重复记录?*//*1. 先按重复字段分组   2. 在每组里找出最小的rowid   3. 把整个表中与上面查询出来的rowid不相等的记录删除掉*/delete from test_t ...

随机推荐

  1. 申请edu邮箱

    https://blog.csdn.net/w305607610/article/details/86771593 手把手教你申请CCC(City Colleges of Chicago)教育邮箱 台 ...

  2. Asp.Net中判断是否登录,及是否有权限?

    不需要在每个页面都做判段, 方法一:只需要做以下处理即可 using System; using System.Collections.Generic; using System.Linq; usin ...

  3. gridcontrol 之标题 GroupPanel设置 (标题设置,屏蔽右键)

    GroupPanel设置 例如gridcontrol显示标题:“gridcontrol小例子” gridView1.GroupPanelText="gridcontrol小例子"; ...

  4. 【题解】T54037 最开始

    传送门 题目大意: 对于\(a+ \frac 1{a^{}}=n\)求$a^{m}+ \frac 1{a^{m}} $,对\(10^9+7\)取模. 题目做法: 乍看此题,没有思路,但是如果用数学办法 ...

  5. 公司IIS 项目公布 注意点

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/sat472291519/article/details/24010721 IIS - 右键 - 属性 ...

  6. JavaScript及jQuery学习小结

    最近几天学习了很多关于JavaScript和jQuery的文章,稍作梳理后,总结如下. 1.jQuery入门系列 环境搭建 只需引用一个jQuery库文件,即可完成jQuery的环境搭建. 选择器 j ...

  7. Oracle数据库基础--存储过程和函数

    一.存储过程和函数 存储过程: 对一个模块的封装 函数: 功能与存储过程几乎一样 区别: 函数必须通过return 关键字返回一个值 存储过程: 不需要return返回值 参数: 输入型参数 输出型参 ...

  8. 【linux】让普通用户执行root的程序

    再有些时候,比如zabbix监控中,需要使用netstat命令查看当前网络链接状态,但是zabbix用户没有权限执行netstat,会导致监控失败,为此使用如下即可解决 chmod +s /bin/n ...

  9. 模拟登陆,selenium,线程池

    一 . 模拟登陆案例(识别验证码)  1 . 打码平台 - 云打码 : www.yundama.com  使用步骤 : - 注册两个账户,普通用户和开发者用户 : - 登陆 普通用户查看余额 登陆开发 ...

  10. BZOJ 2142 礼物 数论

    这道题是求组合数终极版. C(n,m) mod P n>=1e9 m>=1e9 P>=1e9且为合数且piqi<=1e5 拓展lucas定理. 实际上就是一点数论小知识的应用. ...