说说Oracle的rowid

在Oracle中rowid唯一标识每条记录所在的位置,它作为一个伪列在查询中出现:

select rowid,id                                  
from test_table
where rownum<=10 ;
ROWID                      ID
------------------ ----------
AAAVcbAAPAAAAALAAA          1
AAAVcbAAPAAAAALAAB          2
AAAVcbAAPAAAAALAAC          3
AAAVcbAAPAAAAALAAD          4
AAAVcbAAPAAAAALAAE          5
AAAVcbAAPAAAAALAAF          6
AAAVcbAAPAAAAALAAG          7
AAAVcbAAPAAAAALAAH          8
AAAVcbAAPAAAAALAAI          9
AAAVcbAAPAAAAALAAJ         10

rowid是由18个字符组成分4个部分,分别是:

6个字符的对象编号,3个字符的文件号,6个字符的块编号,3个字符的行编号。

每一个字符的取值范围以及对应的数值是:

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

可以看到rowid是一个64进制的表示方式,利用上述对应表即可计算出:

对象编号:AAAVcb  = 87835

文件号:AAP = 41

块号:AAAAAL =11

行号:AAA~AAJ = 0 ~ 9

16进制的转换完全可以交给机器去做,Oracle也是这么认为的,于是提供了一个叫做dbms_rowid的包,它包含了一系列的方法,我们借助这个包就可完成上述的工作了:

select rowid ,
  substr(rowid,1,6) ||' : '|| dbms_rowid.rowid_object(rowid)       "数据对象编号/object_id",
  substr(rowid,7,3) ||' : '|| dbms_rowid.rowid_relative_fno(rowid) "文件编号/file_id",
  substr(rowid,10,6)||' : '|| dbms_rowid.rowid_block_number(rowid) "块编号/block_id",
  substr(rowid,16,3)||' : '|| dbms_rowid.ROWID_ROW_NUMBER(rowid)   "行编号/row_num"
from test_table 
where rownum<=10;
ROWID              数据对象编号/object_id    文件编号/file_id     块编号/block_id      行编号/row_num
------------------ ------------------------- -------------------- -------------------- ---------------
AAAVcbAAPAAAAALAAA AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAA : 0
AAAVcbAAPAAAAALAAB AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAB : 1
AAAVcbAAPAAAAALAAC AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAC : 2
AAAVcbAAPAAAAALAAD AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAD : 3
AAAVcbAAPAAAAALAAE AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAE : 4
AAAVcbAAPAAAAALAAF AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAF : 5
AAAVcbAAPAAAAALAAG AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAG : 6
AAAVcbAAPAAAAALAAH AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAH : 7
AAAVcbAAPAAAAALAAI AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAI : 8
AAAVcbAAPAAAAALAAJ AAAVcb : 87835            AAP : 15             AAAAAL : 11          AAJ : 9

这个结果对不对呢?我们可以这样验证,注意,以下查询需要DBA权限。

首先是object_id:

select 
  owner,object_name,object_id 
from dba_objects 
where object_name='TEST_TABLE';
OWNER      OBJECT_NAME           OBJECT_ID
---------- -------------------- ----------
TEST       TEST_TABLE                8783

然后是文件编号和块编号:

select 
  owner,segment_name,segment_type,extent_id,
  file_id,block_id,blocks,bytes 
from dba_extents 
where segment_name='TEST_TABLE';
OWNER  SEGMENT_NAME  SEGMENT_TYPE   EXTENT_ID  FILE_ID  BLOCK_ID  BLOCKS  BYTES
------ ------------- ------------- ---------- -------- --------- ------- ------
TEST   TEST_TABLE    TABLE                  0       15         8       8  65536
TEST   TEST_TABLE    TABLE                  1       15        16       8  65536

编号为11的块落在了编号为0的exntent上,只能说是验证了一半,接下来我们将数据块dump出来看看,不过做之前先为这一行打上“标记”,看以下过程:

test$logdw@logdw SQL> select rowid,t.* from test_table t where rownum<=5; 

ROWID                      ID DATA
------------------ ---------- ------------------------------
AAAVcbAAPAAAAALAAA          1                              Q
AAAVcbAAPAAAAALAAB          2                              Q
AAAVcbAAPAAAAALAAC          3                              Q
AAAVcbAAPAAAAALAAD          4                              Q
AAAVcbAAPAAAAALAAE          5                              Q

5 rows selected.
test$logdw@logdw SQL> update test_table set data=lpad('killkill',30) where id=1;

1 row updated.
test$logdw@logdw SQL> select rowid,t.* from test_table t where rownum<=5;      

ROWID                      ID DATA
------------------ ---------- ------------------------------
AAAVcbAAPAAAAALAAA          1                       killkill
AAAVcbAAPAAAAALAAB          2                              Q
AAAVcbAAPAAAAALAAC          3                              Q
AAAVcbAAPAAAAALAAD          4                              Q
AAAVcbAAPAAAAALAAE          5                              Q

5 rows selected.
test$logdw@logdw SQL> commit; 

做好了“标记”,可以dump数据块了:

sys$logdw@logdw SQL> select get_trace_name() from dual ; 

GET_TRACE_NAME()
-----------------------------------------------------------------
/u01/app/oracle/diag/rdbms/logdw/logdw/trace/logdw_ora_29284.trc

sys$logdw@logdw SQL> alter system dump datafile 15 block 11 ;

System altered.

打开trc文件,摘录如下:

Start dump data blocks tsn: 10 file#:15 minblk 11 maxblk 11
......
......
Dump of memory from 0x0000002A96F31A00 to 0x0000002A96F33A00
......
......
2A96F31F20 20202020 20202020 20202020 6C696B20  [             kil]
2A96F31F30 6C696B6C 02002C6C 1E03C102 20202020  [lkill,......    ]
......
......
block_row_dump:
tab 0, row 0, @0x4ac
tl: 37 fb: --H-FL-- lb: 0x2  cc: 2
col  0: [ 2]  c1 02
col  1: [30]
 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 6b 69 6c
 6c 6b 69 6c 6c
......
......

你找到killkill了吗?

posted @ 2010-06-26 17:11  killkill  阅读(739)  评论(0编辑  收藏  举报