ROWID是ORACLE中的一個重要的概念。用於定位數據庫中一條記錄的一個相對唯一地址值。通常情況下,該值在該行數據插入到數據庫表時即被確定且唯一。ROWID它是一個偽列,它並不實際存在於表中。它是ORACLE在讀取表中數據行時,根據每一行數據的物理地址信息編碼而成的一個偽列。所以根據一行數據的ROWID能找到一行數據的物理地址信息。從而快速地定位到數據行。數據庫的大多數操作都是通過ROWID來完成的,而且使用ROWID來進行單記錄定位速度是最快的。
要理解索引,必須先搞清楚ROWID。
B-Tree索引的每個索引條目具有兩個字段。第一個字段表示索引的鍵值,對於單列索引來說是一個值;而對於多列索引來說則是多個值組合在一起的。第二個字段表示鍵值所對應的記錄行的ROWID。所以索引能加快查詢速度!
索引值→ROWID->將ROWID換算成一行數據的物理地址->得到一行數據
一、ROWID的格式:
第一部分6位表示:該行數據所在的數據對象的 data_object_id;
第二部分3位表示:該行數據所在的相對數據文件的id;
第三部分6位表示:該數據行所在的數據塊的編號;
第四部分3位表示:該行數據的行的編號;
索引就是保存了rowid后三個部分的信息。索引是物理存在的,而rowid是偽列。所以索引可以用來快速地定位到數據行。
data_object_id
下面以SAKILA數據庫的ACTOR表為例
這里我們要注意將 data_object_id 與 object_id 區分開來,前者是oracle為它的每一個對象唯一分配的id,而后者與表ACTOR對應的“段”有關,是存放表tt的段的id,也就是與存放表tt中數據的物理位置有關:
select owner,object_id,data_object_id,status from dba_objects where object_name='ACTOR';
alter table ACTOR move tablespace users; select owner,object_id,data_object_id,status from dba_objects where object_name='ACTOR';
我們看到當表ACTOR move到了users表空間時,段發生了改變,物理位置發生了變化,從而 DATA_OBJECT_ID 也發生了變化。我們知道表是存放在“表段”中的,索引是存放在“索引段”中的。DATA_OBJECT_ID就是表示存放數據的“數據段對象的id”
相對文件編碼
關於相對文件編碼和絕對文件編號:相對文件id是指相對於表空間,在表空間唯一,絕對文件是指相當於全局數據庫而言的,全局唯一;
select file_name,file_id,relative_fno from dba_data_files;
rowid采用64進制來編碼
編碼方法是:A~Z表示0到25;a~z表示26到51;0~9表示52到61;+表示62;/表示63;剛好64個字符。
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 | / |
二、使用rowid訪問數據的執行計划
SELECT t.*, ''||t.ROWID FROM "SAKILA"."ACTOR" t;
EXPLAIN PLAN FOR select * FROM ACTOR where rowid='AAAYEVAAJAAAACrAAA'; select * from table(DBMS_XPLAN.DISPLAY)
三、例子:如何從rowid計算得到obj#,rfile#,block#,row#
我們演示一下具體的計算方法:
SELECT t.*, ''||t.ROWID FROM "SAKILA"."ACTOR" t;
表sakila的 data_object_id 為 AAAYEVAAJAAAACrAAA的前6位:AAAYEV,那么我們來計算一下 AAAYEV的值到底是多少:
查詢Base64編碼表
碼值 | 字符 |
0 | A |
24 | Y |
4 | E |
21 | V |
select 24 * 64 * 64 + 4 * 64 + 21 from dual;
AAAYEV=24 * 64 * 64 + 4 * 64 + 21=98581
然后我們查詢字典表,看兩種方法得到的值是否相等:
select owner,object_id,data_object_id,status from dba_objects where object_name='ACTOR';
我們看到通過rowid計算得到的data_object_id和通過字典表查到的值相等!
表ACTOR的相對文件編號為 AAAYEVAAJAAAACrAAA 的中的 AAJ,顯然查表可知 AAJ= 9;
我們在再來查詢字典表:
可以看到字典表顯示relative_fno為9的數據文件為C:\APP\ORACLE\ORADATA\ORCL\PDBORCL\SAMPLE_SCHEMA_USERS01.DBF
查詢當前數據庫中的users表空間和對應的數據文件
select file_name,tablespace_name from dba_data_files;
兩者結果一致。
而我們前面執行過:alter table ACTOR move tablespace users;所以兩種方式得到的結果是一致的。
表ACTOR中的第一行數據存放的block的編號為 AAAYEVAAJAAAACrAAA 中的 AAAACr,而AAAACr =2*64+43=171
表ACTOR中的第一行數據存放的行的編號為AAAYEVAAJAAAACrAAA 中的 AAA,顯然值為0,即第一行。
我們也可以通過Oracle提供的存儲過程來計算出上面的值:
SELECT dbms_rowid.rowid_object (ROWID) data_object_id, dbms_rowid.rowid_relative_fno (ROWID) relative_fno, dbms_rowid.rowid_block_number (ROWID) block_no, dbms_rowid.rowid_row_number (ROWID) row_no FROM ACTOR;
顯然這個結果和我們手動計算的結果是一致的。