唯一性索引(Unique Index)與普通索引(Normal Index)差異(中)

realkid4發表於2011-06-17

 

宣告:本篇知識方法受到dbsnake相關文章啟發,特此感謝!

 

在本系列的前篇(http://space.itpub.net/17203031/viewspace-700089)裡,我們探討了唯一索引和普通索引在應用角度上的差異。實驗中,我們發現在基礎資料相同的情況下,兩型別索引在體積上有細微的差異,這使得我們可以猜測兩種型別索引在儲存結構上的可能差異。

 

本篇打算從儲存結構入手,探討兩種型別索引的差異。

 

1、  環境準備

 

同前篇相同,準備相同的資料索引列取值,建立不同型別的索引。為了減少整理資料量,所以選擇較小的資料集。

 

 

SQL> select * from v$version where rownum<2;

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

 

SQL> create table t (id number, vid number);

Table created

 

SQL> select * from t;

        ID        VID

---------- ----------

         1          1

         2          2

         3          3

 

//建立普通索引

SQL> create index idx_t_normalid on t(id);

Index created

 

//建立唯一性索引

SQL> create unique index idx_t_uniqueid on t(vid);

Index created

 

SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);

PL/SQL procedure successfully completed

 

SQL> col object_name for a20;

SQL> select object_name, object_id from dba_objects where object_name in ('IDX_T_NORMALID','IDX_T_UNIQUEID');

 

OBJECT_NAME           OBJECT_ID

-------------------- ----------

IDX_T_NORMALID            75141

IDX_T_UNIQUEID            75142

 

 

 

2、  普通索引邏輯結構分析

 

思路是從索引樹入手,現將索引段結構Dump出去,檢查整體分佈情況。

 

//獲取跟蹤檔案位置

SQL> select name, value from  v$diag_info where name='Default Trace File';

 

NAME                           VALUE

------------------------------ --------------------------------------------------------------------------------

Default Trace File             /u01/diag/rdbms/wilson/wilson/trace/wilson_ora_5850.trc

 

//將索引樹Dump出到Trace檔案

SQL> alter session set events 'immediate trace name treedump level 75141';

Session altered

 

 

注意:v$diag_info檢視是Oracle 11g中新推出的檢視型別,其中包括了所有診斷檔案的位置和目錄。其中Default Trace File專案就是當前會話對應的Trace File路徑和名稱,不需要我們過去那樣使用自定義函式查詢。

 

此時,我們檢索Trace File內容,核心片段如下:

 

 

*** 2011-06-15 01:47:04.350

*** SESSION ID:(20.13) 2011-06-15 01:47:04.350

*** CLIENT ID:() 2011-06-15 01:47:04.350

*** SERVICE NAME:(wilson) 2011-06-15 01:47:04.350

*** MODULE NAME:(PL/SQL Developer) 2011-06-15 01:47:04.350

*** ACTION NAME:(Command Window - New) 2011-06-15 01:47:04.350

 

----- begin tree dump

leaf: 0x415af1 4283121 (0: nrow: 3 rrow: 3)

----- end tree dump

 

上面的Tree Dump結果,說明因為索引很小(只有三行記錄),只有一個索引塊中包括資料。其中葉子節點為3個,該索引塊的地址為(0x415af1,十進位制表示為4283121)。

 

索引塊4283121對應的實際檔案和資料塊資訊是什麼呢?使用dbms_utiliy包的相關方法,可以幫助獲取到對應檔案和塊號。

 

 

SQL> select dbms_utility.data_block_address_file(4283121), dbms_utility. data_block_address_block(4283121) from dual;

 

DBMS_UTILITY.DATA_BLOCK_ADDRES DBMS_UTILITY.DATA_BLOCK_ADDRES

------------------------------ ------------------------------

                             1                          88817

 

 

索引塊在檔案1,對應塊號為88817

 

使用邏輯dump出塊的結構資訊。

 

 

SQL> alter system dump datafile 1 block 88817;

System altered

 

 

DUMP在跟蹤檔案上的核心內容為:

 

 

--核心片段

Block dump from cache:

Dump of buffer cache at level 4 for tsn=0, rdba=4283121

BH (0x2dff3578) file#: 1 rdba: 0x00415af1 (1/88817) class: 1 ba: 0x2dea0000

 

Block header dump:  0x00415af1

 Object id on Block? Y

 seg/obj: 0x12585  csc: 0x00.396f48  itc: 2  flg: -  typ: 2 - INDEX

     fsl: 0  fnx: 0x0 ver: 0x01

 

row#0[8020] flag: ------, lock: 0, len=12

col 0; len 2; (2):  c1 02

col 1; len 6; (6):  00 41 5a e9 00 00

row#1[8008] flag: ------, lock: 0, len=12

col 0; len 2; (2):  c1 03

col 1; len 6; (6):  00 41 5a e9 00 01

row#2[7996] flag: ------, lock: 0, len=12

col 0; len 2; (2):  c1 04

col 1; len 6; (6):  00 41 5a e9 00 02

----- end of leaf block dump -----

End dump data blocks tsn: 0 file#: 1 minblk 88817 maxblk 88817

 

 

實際Dump出的資訊很多,篇幅原因,筆者只是將最核心的部分加以展現。

 

首先關注最後的三個row#資訊,該部分表示三個葉子節點的核心內容。其中[]中包括的是葉子節點在索引塊中的相對偏移量。Len表示該葉子所佔用空間長度是多少(注意:此處的Normal Index葉子節點佔用12長度)。

 

最後,觀察行與行之間的偏移量差(7996-8008-8020),正好是行間的距離12

 

每個葉子節點包括兩個column內容,分別佔據2位和6位。由於是使用16進位制形式儲存,我們不能直接看出內容含義。下面實驗可以幫助我們進行猜測:

 

 

--關鍵資料演算:

 

SQL> select dump(1,1016) from dual;

DUMP(1,1016)

-----------------

Typ=2 Len=2: c1,2

 

SQL> select dump(2,1016) from dual;

DUMP(2,1016)

-----------------

Typ=2 Len=2: c1,3

 

SQL> select dump(3,1016) from dual;

DUMP(3,1016)

-----------------

Typ=2 Len=2: c1,4

 

 

我們的索引列取值就是1234,上面使用DUMP函式的結果,告訴我們跟蹤檔案中每個row的第一列表示的是索引列取值。索引葉子節點內容無非就是rowid和索引鍵值。那麼row的第二列含義必然可能就是rowid相關內容。

 

只對第三行資料進行試算:

 

 

16進製取值:00 41 5a e9 00 02

 2進製取值:00000000 01000001 01011010 11101001 00000000 00000010

 

 

根據相關資料,我們進行如下設定:

 

 

File_ID:前10位:00000000 01=1

Block_id 中間22位:000001 01011010 11101001=88809

Slot_id00000000 00000010=2

 

 

如果改值是rowid,那麼一定和資料表T行的rowid存在對應關係。

 

 

SQL> select t.*,t.rowid, dbms_rowid.rowid_relative_fno(t.rowid) fno, dbms_rowid.rowid_block_number(t.rowid)

blockn,dbms_rowid.rowid_row_number(t.rowid) rown from t;

 

        ID        VID ROWID                     FNO     BLOCKN       ROWN

---------- ---------- ------------------ ---------- ---------- ----------

         1          1 AAASWCAABAAAVrpAAA          1      88809          0

         2          2 AAASWCAABAAAVrpAAB          1      88809          1

         3          3 AAASWCAABAAAVrpAAC          1      88809          2

 

 

Rowid中包括的資訊:檔案編號+物件編號+塊編號+塊內slot編號;索引葉子中的第二列資料,已經能夠提供檔案編號、塊編號和內部slot編號。物件編號是進行選取Select時候就帶入的。

 

 

3、普通索引物理結構分析

 

從上面的邏輯結構,我們看到了儲存的邏輯結構。下面根據資訊,我們到物理儲存層面看普通索引結構。注意,此處我們只關注一行資料,就是row2[7996]的葉子節點。

 

我們現在有該索引的檔案編號和塊編號,缺乏就是實際的偏移量。下面首先計算出實際的偏移量。

 

 

SQL> select file_name, tablespace_name from dba_data_files where file_id=1;

 

FILE_NAME                                                                        TABLESPACE_NAME

-------------------------------------------------------------------------------- ------------------------------

/u01/oradata/WILSON/datafile/o1_mf_system_6bcsnqfc_.dbf                          SYSTEM

 

 

SQL> select tablespace_name,SEGMENT_SPACE_MANAGEMENT from dba_tablespaces where tablespace_name='SYSTEM';

 

TABLESPACE_NAME                SEGMENT_SPACE_MANAGEMENT

------------------------------ ------------------------

SYSTEM                         MANUAL

 

 

資料表索引對應的表空間SYSTEM,是使用MSSM進行Segment Space Management。所以,計算出的偏移量就是:

 

 

7996+68+(2-1)*24=8088

 

 

下面使用BBED工具直接進行塊讀取,注意,首先需要關閉資料庫。

 

 

==dump

[oracle@oracle11g test]$ bbed parfile=par.txt

Password:

 

BBED: Release 2.0.0.0.0 - Limited Production on Wed Jun 15 02:05:20 2011

Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

************* !!! For Oracle Internal Use only !!! ***************

 

BBED> info  

 File#  Name                                                        Size(blks)

 -----  ----                                                        ----------

     1  /u01/oradata/WILSON/datafile/o1_mf_system_6bcsnqfc_.dbf         106240

     (篇幅原因,有省略……

 

//定位到指定的檔案和塊位置(也可以使用set file 1 block 88817

BBED> set dba 0x00415af1

        DBA             0x00415af1 (4283121 1,88817)

 

//定位塊內的偏移量

BBED> set offset 8088

        OFFSET          8088

 

//DUMP顯示出來

BBED> dump

 File: /u01/oradata/WILSON/datafile/o1_mf_system_6bcsnqfc_.dbf (1)

 Block: 88817            Offsets: 8088 to 8191           Dba:0x00415af1

------------------------------------------------------------------------

 000002c1 04060041 5ae90002 000002c1 03060041 5ae90001 000002c1 02060041

 5ae90000 0d000040 15000002 00401500 000203c2 085eac00 01150015 00004015

 00000100 40150000 0103c208 5aac0001 11001100 0040110f 00090040 110f0009

 03c20858 0106496f

 

 <32 bytes per line>

 

 

再看一下我們將row2匯出的資訊:

 

 

row#2[7996] flag: ------, lock: 0, len=12

col 0; len 2; (2):  c1 04

col 1; len 6; (6):  00 41 5a e9 00 02

 

 

注意:兩個標記0x020x06的作用是標記列Column資訊,用於分割。

 

4、  區域性結論

 

對普通索引結構來說,索引葉子節點上儲存索引鍵值和對應資料行rowid兩者是以行中不同column的方式進行儲存,鍵值在前,rowid在後。

 

 

下面我們使用相同的流程處理Unique Index,檢查相關的儲存結構。

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-700163/,如需轉載,請註明出處,否則將追究法律責任。

相關文章