oracle rowid (转载)

教程发布:风哥 教程分类:ITPUX技术网 更新日期:2022-02-12 浏览学习:292

oracle rowid (转载)

[color=#047400]oracle rowid搞oracle的人都很清楚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#的区别可以参考biti_rainy的一篇blog
[color=#047400]http://blog.itpub.net/post/330/22749

继续上面的话题,我们猜想oracle实现rfile#和file#的转换是不是由一些递归sql来实现,所以我们做了一个测试来看是否oracle从file$等基表中实现呢?我们做了一个10046 trace,发现并不存在相应的递归sql,那oracle怎么实现呢?可能是直接取一些x$table中的数据了吧,那哪个x$table保留这些信息呢?

x$kccfe!!!

SQL 10G>desc x$kccfe
Name Null? Type
----------------------------------------- -------- ----------------------------
ADDR RAW(4)
INDX NUMBER
INST_ID NUMBER
FENUM NUMBER
FECSZ NUMBER
FEBSZ NUMBER
FESTA NUMBER
FECRC_SCN VARCHAR2(16)
FECRC_TIM VARCHAR2(20)
FECRC_THR NUMBER
FECRC_RBA_SEQ NUMBER
FECRC_RBA_BNO NUMBER
FECRC_RBA_BOF NUMBER
FECRC_ETB RAW(132)
FECPS VARCHAR2(16)
FECPT VARCHAR2(20)
FECPC NUMBER
FESTS VARCHAR2(16)
FESTT VARCHAR2(20)
FEBSC VARCHAR2(16)
FEFNH NUMBER
FEFNT NUMBER
FEDUP NUMBER
FEURS VARCHAR2(16)
FEURT VARCHAR2(20)
FEOFS VARCHAR2(16)
FEONC_SCN VARCHAR2(16)
FEONC_TIM VARCHAR2(20)
FEONC_THR NUMBER
FEONC_RBA_SEQ NUMBER
FEONC_RBA_BNO NUMBER
FEONC_RBA_BOF NUMBER
FEONC_ETB RAW(132)
FEPOR NUMBER
FETSN NUMBER
FETSI NUMBER
FERFN NUMBER
FEPFT NUMBER
FEDOR NUMBER
FEPDI NUMBER
FEFDB NUMBER
FEPLG_SCN VARCHAR2(16)
FEPAX NUMBER
FEFLG NUMBER

从这个x$table中oracle可以实现file和rfile的转换。

最后我们来看一个例子

SQL 10G>desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
A NUMBER
B VARCHAR2(32)

test是一张分区表

SQL 10G>select table_name,partition_name,tablespace_name from dba_tab_partitions where table_name='TEST';
TABLE_NAME PARTITION_NAME TABLESPACE_NAME
------------------------------ ------------------------------ ------------------------------
TEST P1 TESTROWID
TEST P2 TESTROWID

这条记录所在的物理位置

SQL 10G>select dbms_rowid.ROWID_OBJECT(rowid) data_object_id#,dbms_rowid.ROWID_RELATIVE_FNO(rowid) rfile#,dbms_rowid.ROWID_BLOCK_NUMBER(rowid) block#,dbms_rowid.ROWID_ROW_NUMBER(rowid) row# from test ;
DATA_OBJECT_ID# RFILE# BLOCK# ROW#
--------------- ---------- ---------- ----------
63665 28 15 0

我们对它创建全局索引

SQL 10G>create index ind_test on test(a);
Index created.

再创建本地索引

SQL 10G>create index ind_test_local on test(b) local;
Index created.

SQL 10G>select dump(rowid,16) rid from test;
RID
----------------------------------------------------------------------------
Typ=69 Len=10: 0,0,f8,b1,7,0,0,f,0,0

去看看全局索引和本地索引中rowid entry的区别

SQL 10G>select header_block,header_file from dba_segments where segment_name='IND_TEST';
HEADER_BLOCK HEADER_FILE
------------ -----------
1403 4

SQL 10G>select header_block,header_file from dba_segments where segment_name='IND_TEST_LOCAL';
HEADER_BLOCK HEADER_FILE
------------ -----------
11 33
11 34

SQL 10G>ALTER SYSTEM DUMP DATAFILE 4 BLOCK 1404;
System altered.

SQL 10G>ALTER SYSTEM DUMP DATAFILE 33 BLOCK 12;
System altered.

全局索引ind_test的rowid entry

col 1; len 10; (10): 00 00 f8 b1 07 00 00 0f 00 00

本地索引ind_test_local的rowid entry

col 1; len 6; (6): 07 00 00 0f 00 00

可以看出本地索引存储了6bytes rowid,全局索引存储了10bytes rowid

再来看一下00 00 f8 b1 07 00 00 0f 00 00
转换成bit就是
00000000 00000000 11111000 10110001 00000111 00000000 00000000 00001111 00000000 00000000

32bit的 data_object_id#,10 bit 的 rfile#,22bit 的 block#,16 bit 的 row#.

00000000 00000000 11111000 10110001 data_object_id#
转换成10进制就是

2^15+2^14+2^13+2^12+2^11+2^7+2^5+2^4+2^0=63665

00000111 00 rfile#

2^4+2^3+2^2=28
0000000000000000001111 block#

2^3+2^2+2^1+2^0=15

0000000000000000 rowi#

0

SQL 10G>select dbms_rowid.ROWID_OBJECT(rowid) data_object_id#,dbms_rowid.ROWID_RELATIVE_FNO(rowid) rfile#,dbms_rowid.ROWID_BLOCK_NUMBER(rowid) block#,dbms_rowid.ROWID_ROW_NUMBER(rowid) row# from test ;
DATA_OBJECT_ID# RFILE# BLOCK# ROW#
--------------- ---------- ---------- ----------
63665 28 15 0

验证通过

再来看一下如果file#超过1023后oracle会怎么处理

SQL 10G>select file#,ts#,rfile# from v$datafile where file#>1023;
FILE# TS# RFILE#
---------- ---------- ----------
1024 14 1
1025 14 3
1026 14 4
1027 14 5
1028 14 6
1029 14 7
1030 14 8
1031 14 9
1032 14 10
1033 14 11
1034 14 12
FILE# TS# RFILE#
---------- ---------- ----------
1035 14 13
1036 14 14
1037 15 14

可以看到在一个tablespace里面rfile#从1开始到1023

SQL 10G>select file#,rfile# from v$datafile where ts#=14 order by file#;
FILE# RFILE#
---------- ----------
2 2
15 15
16 16
17 17
18 18
19 19
20 20
21 21
22 22
23 23
24 24
。。。。。。
FILE# RFILE#
---------- ----------
1015 1015
1016 1016
1017 1017
1018 1018
1019 1019
1020 1020
1021 1021
1022 1022
1023 1023
1024 1
1025 3
FILE# RFILE#
---------- ----------
1026 4
1027 5
1028 6
1029 7
1030 8
1031 9
1032 10
1033 11
1034 12
1035 13
1036 14

本文标签:
本文标题:oracle rowid (转载)
网站声明:本文由风哥整理发布,转载请保留此段声明,本站所有内容将不对其使用后果做任何承诺,请读者谨慎使用!
【上一篇】
【下一篇】