[20231024]NULL值在索引的情況.txt

lfree發表於2023-10-30

[20231024]NULL值在索引的情況.txt

--//如果全部鍵值是NULL,oracle不儲存該鍵值在索引中.如果表後面幾個欄位是NULL值,oracle不會浪費空間儲存相關資訊.
--//因為在資料塊中存在一個儲存欄位數量的標識,而索引塊不存在這個標識。這樣對於索引欄位最後幾個欄位為NULL的情況,oracle是
--//如何操作的呢? 如果索引尾部幾個欄位是NULL呢?以前沒有關注這個問題,測試看看.

1.環境:
SCOTT@test01p> @ver1
PORT_STRING                    VERSION        BANNER                                                                               CON_ID
------------------------------ -------------- -------------------------------------------------------------------------------- ----------
IBMPC/WIN_NT64-9.1.0           12.2.0.1.0     Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production              0

2.測試:
SCOTT@test01p> create table empx as select * from emp;
Table created.

SCOTT@test01p> create unique index pk_empx on empx (empno,comm);
Index created.

SCOTT@test01p> select * from empx order by 1;
     EMPNO ENAME      JOB              MGR HIREDATE                   SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
      7369 SMITH      CLERK           7902 1980-12-17 00:00:00        800                    20
      7499 ALLEN      SALESMAN        7698 1981-02-20 00:00:00       1600        300         30
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~      
      7521 WARD       SALESMAN        7698 1981-02-22 00:00:00       1250        500         30
      7566 JONES      MANAGER         7839 1981-04-02 00:00:00       2975                    20
      7654 MARTIN     SALESMAN        7698 1981-09-28 00:00:00       1250       1400         30
      7698 BLAKE      MANAGER         7839 1981-05-01 00:00:00       2850                    30
      7782 CLARK      MANAGER         7839 1981-06-09 00:00:00       2450                    10
      7788 SCOTT      ANALYST         7566 1987-04-19 00:00:00       3000                    20
      7839 KING       PRESIDENT            1981-11-17 00:00:00       5000                    10
      7844 TURNER     SALESMAN        7698 1981-09-08 00:00:00       1500          0         30
      7876 ADAMS      CLERK           7788 1987-05-23 00:00:00       1100                    20
      7900 JAMES      CLERK           7698 1981-12-03 00:00:00        950                    30
      7902 FORD       ANALYST         7566 1981-12-03 00:00:00       3000                    20
      7934 MILLER     CLERK           7782 1982-01-23 00:00:00       1300                    10
14 rows selected.
--//我按照empno排序,這樣kd_off[2]指向的就是empno的最小鍵值。

SCOTT@test01p> @ seg2 pk_empx
SCOTT@test01p> @ pr
==============================
SEG_MB                        : 0
SEG_OWNER                     : SCOTT
SEG_SEGMENT_NAME              : PK_EMPX
SEG_PARTITION_NAME            :
SEG_SEGMENT_TYPE              : INDEX
SEG_TABLESPACE_NAME           : USERS
BLOCKS                        : 8
HDRFIL                        : 11
HDRBLK                        : 410
PL/SQL procedure successfully completed.
--//dba =11,411 就是索引的root,empx表僅僅14條記錄,該地址也同時是葉子節點.

3.bbed觀察:
BBED> set dba 11,412
        DBA             0x02c0019c (46137756 11,412)
--//windwos bbed版本 塊偏移+1 ,因為無法識別12c的資料檔案OS頭.

BBED> map
 File: D:\APP\ORACLE\ORADATA\TEST\TEST01P (11)
 Block: 412                                   Dba:0x02c0019c
------------------------------------------------------------
 KTB Data Block (Index Leaf)
 struct kcbh, 20 bytes                      @0
 struct ktbbh, 72 bytes                     @20
 struct kdxle, 32 bytes                     @100
 b2 kd_off[14]                              @132
 ub1 freespace[7784]                        @160
 ub1 rowdata[188]                           @7944
 ub4 tailchk                                @8188

BBED> map
 File: D:\APP\ORACLE\ORADATA\TEST\TEST01P (11)
 Block: 412                                   Dba:0x02c0019c
------------------------------------------------------------
 KTB Data Block (Index Leaf)
 struct kcbh, 20 bytes                      @0
 struct ktbbh, 72 bytes                     @20
 struct kdxle, 32 bytes                     @100
 b2 kd_off[14]                              @132
 ub1 freespace[7805]                        @160
 ub1 rowdata[167]                           @7965
 ub4 tailchk                                @8188

BBED> p kdxle
struct kdxle, 32 bytes                      @100
   struct kdxlexco, 16 bytes                @100
      ub1 kdxcolev                          @100      0x00
      ub1 kdxcolok                          @101      0x00
      ub1 kdxcoopc                          @102      0x80
      ub1 kdxconco                          @103      0x02       --//索引包含2個欄位.如果上面建立的索引非唯 一,這裡是3,
                                                                 --//包括rowid相關資訊作為索引的一部分
      ub4 kdxcosdc                          @104      0x00000000
      sb2 kdxconro                          @108      14         --//14條記錄.
      b2 kdxcofbo                           @110      64
      b2 kdxcofeo                           @112      7848
      b2 kdxcoavs                           @114      7784
   b2 kdxlespl                              @116      0
   sb2 kdxlende                             @118      0
   ub4 kdxlenxt                             @120      0x00000000
   ub4 kdxleprv                             @124      0x00000000
   ub1 kdxledsz                             @128      0x06      --//索引的rowid在前面,沒有長度指示器,佔6位元組.
                                                                --//如果是0,非唯 一索引。是10是全域性唯 一索引。
                                                                --//是8是cluster index。
   ub1 kdxleunuse                           @129      0x00

BBED> p kd_off
b2 kd_off[0]                                @132      8036     --//8036+100(kdxle的偏移)=8136 表示索引的結尾,中間還保留
                                                               --//8188-8136 = 52,不知道什麼用處。
b2 kd_off[1]                                @134      0        --//kd_off[0],kd_off[1]執行的偏移不對,我估計oracle改變了
                                                               --//kdxle結構,這4個位元組的內容屬於kdxle。
b2 kd_off[2]                                @136      8023
b2 kd_off[3]                                @138      8008
b2 kd_off[4]                                @140      7993
b2 kd_off[5]                                @142      7980
b2 kd_off[6]                                @144      7965
b2 kd_off[7]                                @146      7952
b2 kd_off[8]                                @148      7939
b2 kd_off[9]                                @150      7926
b2 kd_off[10]                               @152      7913
b2 kd_off[11]                               @154      7899
b2 kd_off[12]                               @156      7886
b2 kd_off[13]                               @158      7874
--//以前提過kd_off指向的鍵值是按照鍵值排序的.注意bbed的版本有問題,實際上從kd_off[2]開始.
   
BBED> x /rnnn *kd_off[2]
rowdata[179]                                @8123
------------
flag@8123:     0x00 (NONE)
lock@8124:     0x00
keydata[6]:    0x02  0xc0  0x01  0x93  0x00  0x00
data key:
col    0[3] @8132: 7369
col    1[0] @8136: *NULL*
--//8123+1+1+6+1+3+1 = 8136
--//8188-8136 = 52,確實保留52位元組在資料塊尾部,為什麼?

BBED> x /rnnn *kd_off[3]
rowdata[164]                                @8108
------------
flag@8108:     0x00 (NONE)
lock@8109:     0x00
keydata[6]:    0x02  0xc0  0x01  0x93  0x00  0x01
data key:
col    0[3] @8117: 7499
col    1[2] @8121: 300

--//選擇16進位制看看.
BBED> x /rxxx *kd_off[2]
rowdata[179]                                @8123
------------
flag@8123:     0x00 (NONE)
lock@8124:     0x00
keydata[6]:    0x02  0xc0  0x01  0x93  0x00  0x00
data key:
col    0[3] @8132:  0xc2  0x4a  0x46
col    1[0] @8136: *NULL*

BBED> p tailchk
ub4 tailchk                                 @8188     0xb5370601

BBED> dump /v offset 8123 count 100
 File: D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF (11)
 Block: 412     Offsets: 8123 to 8191  Dba:0x02c0019c
-------------------------------------------------------
 000002c0 01930000 03c24a46 ff000000 l ...?....翵F....
 00000000 00000000 00000000 00000000 l ................
 00000000 00000000 00000000 00000000 l ................
 00000000 00000000 00000000 00000000 l ................
 00010637 b5                         l ...7
 <16 bytes per line>

BBED> dump /v offset 8123 count 13
 File: D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF (11)
 Block: 412     Offsets: 8123 to 8135  Dba:0x02c0019c
-------------------------------------------------------
 000002c0 01930000 03c24a46 ff       l ...?....翵F.
 <16 bytes per line>

--//可以發現NULL儲存的資訊0xff,前面沒有長度指示器。有點奇怪為什麼索引在底部保留一段沒有儲存資訊,佔用52位元組.

BBED> x /rxxx *kd_off[5]
rowdata[136]                                @8080
------------
flag@8080:     0x00 (NONE)
lock@8081:     0x00
keydata[6]:    0x02  0xc0  0x01  0x93  0x00  0x03
data key:
col    0[3] @8089:  0xc2  0x4c  0x43
col    1[0] @8093: *NULL*

BBED> dump /v offset 8080 count 13
 File: D:\APP\ORACLE\ORADATA\TEST\TEST01P\USERS01.DBF (11)
 Block: 412     Offsets: 8080 to 8092  Dba:0x02c0019c
-------------------------------------------------------
 000002c0 01930003 03c24c43 ff       l ...?....翷C.
<16 bytes per line>

--//也就是索引是保留NULL值的,即使在索引欄位的尾部。

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

相關文章