天天看點

Index的原理

本文章為網絡筆記,看了warehouse老師的視訊受益匪淺,更是感覺自己技術太過初級,特寫了本筆記,友善以後反複學習!

如有任何不妥,請發郵件至[email protected]删除文章!

關于warehouse:

http://blog.itpub.net/19602/viewspace-1059211/

11gR2視訊第四版 8_03_index的原理

1.index

bitmap index

(位圖索引)

b-tree index(balance(平衡) tree)

不是二叉樹,特點是根節點(

root

)很少,葉子節點(

leaf

)很多,是以通俗的講這顆樹不高是以查找的很快,資料最終都是放在葉子節點上

Index的原理

root

下不止有一個

branches

,可以有多個,

branches

下面還有

branches

那時候的資料很大了,差不多就上億了

Index的原理

1.為啥要建索引?

2.索引為什麼會提高查詢效率?

3.是不是有了索引之後就一定會提高查詢效率?

索引可以提高查詢效率,但是它本身也是一個

segment

,需要大量的存儲空間,做

DML

操作的時候索引也需要維護

實驗:

SQL> create table tt2 tablespace users as select * from dba_objects;

Table created.
SQL> insert into tt2 select * from tt2;

15358 rows created.

SQL> insert into tt2 select * from tt2;

30716 rows created.

SQL> insert into tt2 select * from tt2;

61432 rows created.

SQL> insert into tt2 select * from tt2;

122864 rows created.

SQL> select count(1) from tt2;

  COUNT(1)
----------
    245728
           

建一個索引,索引是一個

segment

,是以他也有

metadata id

data id

SQL> create index idx_tt2 on tt2(object_id) tablespace users;

Index created.
           

檢視一下這個

index

metadata id

data id

Oracle

有一條内部指令可以分析

b-tree

索引的結構,這個指令就用到了

object_id

(中繼資料

id

SQL> select object_id,data_object_id from dba_objects where object_name = 'IDX_TT2';

 OBJECT_ID DATA_OBJECT_ID
---------- --------------
     15762	    15762
           

這個内容就放在了為這個

session

服務的

process

trace

檔案裡

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

Session altered.
           

目前

session sid

SQL> select distinct sid from v$mystat;

       SID
----------
       136
           

找出為這個

session

服務的

process

的作業系統的程序号

SELECT *
       FROM v$process
      WHERE ADDR = (SELECT paddr FROM v$session WHERE sid = '136')
           
Index的原理

背景程序

dump

下來的檔案就是在

background_dump_dest

SQL> show parameter dump;

NAME				     	TYPE	 	VALUE
-------------------------- ----------- ------------------------------
background_core_dump		string	 	partial
background_dump_dest		string	 	/u01/app/oracle/diag/rdbms/buy/sales/trace
core_dump_dest			    string	 	/u01/app/oracle/diag/rdbms/buy/sales/cdump
max_dump_file_size		    string	 	unlimited
shadow_core_dump		    string	 	partial
user_dump_dest			    string	 	/u01/app/oracle/diag/rdbms/buy/sales/trace
           

就是這個

sales_ora_6598.trc

[[email protected] /u01/app/oracle/diag/rdbms/buy/sales/trace]$ ls -lrt
-rw-r----- 1 oracle oinstall    865 Mar 17 10:40 sales_mman_5417.trc
-rw-r----- 1 oracle oinstall     60 Mar 17 10:40 sales_ora_5451.trm
-rw-r----- 1 oracle oinstall    993 Mar 17 10:40 sales_ora_5451.trc
-rw-r----- 1 oracle oinstall     69 Mar 17 10:40 sales_j000_5473.trm
-rw-r----- 1 oracle oinstall    981 Mar 17 10:40 sales_j000_5473.trc
-rw-r----- 1 oracle oinstall     80 Mar 17 10:41 sales_dbrm_5413.trm
-rw-r----- 1 oracle oinstall   1282 Mar 17 10:41 sales_dbrm_5413.trc
-rw-r----- 1 oracle oinstall 175003 Mar 17 12:30 alert_sales.log
-rw-r----- 1 oracle oinstall     71 Mar 17 14:23 sales_ora_6598.trm
-rw-r----- 1 oracle oinstall  29781 Mar 17 14:23 sales_ora_6598.trc
-rw-r----- 1 oracle oinstall    625 Mar 17 14:37 sales_mmon_5430.trm
-rw-r----- 1 oracle oinstall   6666 Mar 17 14:37 sales_mmon_5430.trc
           

trace

檔案的一部分

Trace file /u01/app/oracle/diag/rdbms/buy/sales/trace/sales_ora_6598.trc
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
ORACLE_HOME = /u01/app/oracle/product/11.2.0/dbhome_1
System name:    Linux
Node name:      oracle
Release:        3.10.0-862.el7.x86_64
Version:        #1 SMP Fri Apr 20 16:44:24 UTC 2018
Machine:        x86_64
VM name:        VMWare Version: 6
Instance name: sales
Redo thread mounted by this instance: 1
Oracle process number: 19
Unix process pid: 6598, image: [email protected] (TNS V1-V3)


*** 2021-03-17 14:23:36.913
*** SESSION ID:(136.23) 2021-03-17 14:23:36.913
*** CLIENT ID:() 2021-03-17 14:23:36.913
*** SERVICE NAME:(SYS$USERS) 2021-03-17 14:23:36.913
*** MODULE NAME:([email protected] (TNS V1-V3)) 2021-03-17 14:23:36.913
*** ACTION NAME:() 2021-03-17 14:23:36.913
##下面這個就是已經生成index了,這個branch可以看成是一個特殊的root,因為資料量比較少是以branch下面就是leaf
----- begin tree dump
branch: 0x100010b 16777483 (0: nrow: 526, level: 1)
   leaf: 0x100010c 16777484 (-1: nrow: 512 rrow: 512)
   leaf: 0x100010d 16777485 (0: nrow: 512 rrow: 512)
   leaf: 0x100010e 16777486 (1: nrow: 512 rrow: 512)
   leaf: 0x100010f 16777487 (2: nrow: 481 rrow: 481)
           

再插入一些資料,索引對應的

segment

也是會增大的

SQL> insert into tt2 select * from tt2;

245728 rows created.

SQL> commit;

Commit complete.

SQL> select count(1) from tt2;

  COUNT(1)
----------
    491456
    
SQL> alter session set events 'immediate trace name treedump level 15762';

Session altered.
           

重新打開這個檔案

sales_ora_6598.trc

讓他加載一下,注意這個

begin tree dump

上面的時間是不是對應執行

alter session set events

的時間,因為這個檔案是累加的防止上面的檔案幹擾,還是隻截取一部分

*** 2021-03-17 14:49:45.710
----- begin tree dump
branch: 0x100010b 16777483 (0: nrow: 2, level: 2)	##這個branch其實就是可以看成是root
   branch: 0x1001073 16781427 (-1: nrow: 482, level: 1)	##這裡有一個branch(第一個)
      leaf: 0x100010c 16777484 (-1: nrow: 512 rrow: 512)
      leaf: 0x1001064 16781412 (0: nrow: 512 rrow: 512)
      leaf: 0x100010d 16777485 (1: nrow: 512 rrow: 512)
      leaf: 0x1001068 16781416 (2: nrow: 512 rrow: 512)
      leaf: 0x100010e 16777486 (3: nrow: 512 rrow: 512)
      leaf: 0x1001045 16781381 (4: nrow: 512 rrow: 512)
      leaf: 0x100010f 16777487 (5: nrow: 480 rrow: 480)
      leaf: 0x1001055 16781397 (6: nrow: 481 rrow: 481)
      leaf: 0x1000110 16777488 (7: nrow: 479 rrow: 479)
      leaf: 0x1001059 16781401 (8: nrow: 463 rrow: 463)
      leaf: 0x1000111 16777489 (9: nrow: 482 rrow: 482)
           

一共是有兩個

branch

,然後就是

leaf

了,是以

balance tree

的特點就是扁平的

leaf: 0x1000efd 16781053 (479: nrow: 478 rrow: 478)
      leaf: 0x1001303 16782083 (480: nrow: 480 rrow: 480)
   branch: 0x1001077 16781431 (0: nrow: 570, level: 1)	##這裡也是一個branch(第二個)
      leaf: 0x1000efe 16781054 (-1: nrow: 480 rrow: 480)
      leaf: 0x1001307 16782087 (0: nrow: 462 rrow: 462)
      leaf: 0x1000eff 16781055 (1: nrow: 482 rrow: 482)
      leaf: 0x1001317 16782103 (2: nrow: 477 rrow: 477)
      leaf: 0x1000f02 16781058 (3: nrow: 499 rrow: 499)
      leaf: 0x100131b 16782107 (4: nrow: 459 rrow: 459)
      leaf: 0x1000f03 16781059 (5: nrow: 481 rrow: 481)
      leaf: 0x1001250 16781904 (6: nrow: 477 rrow: 477)
           

下面分析葉子節點(

leaf

使用

Oracle

函數轉化一下

16

進制數驗證一下

SQL> select to_number('100010c','xxxxxxx') from dual;

TO_NUMBER('100010C','XXXXXXX')
------------------------------
		      16777484
           

知道了十進制數之後

Oracle

提供了包,包中有函數可以分解成是哪個資料檔案上的哪個塊

SQL> select dbms_utility.data_block_address_file(16777484) from dual;

DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(16777484)
----------------------------------------------
					     4

SQL> select dbms_utility.data_block_address_block(16777484) from dual;

DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(16777484)
-----------------------------------------------
					    268
           

知道這個

index

中的

leaf

是在哪個塊了就把這個塊

dump

下來

SQL> alter system dump datafile 4 block 268;

System altered.
           
SQL> select distinct sid from v$mystat;

       SID
----------
       137
       
SQL> select spid from v$process where addr = (select paddr from v$session where sid = '137');

SPID
------------------------
4691

SQL> show parameter dump;

NAME				     TYPE	 VALUE
------------------------ ------- ------------------------------
background_core_dump	 string	 partial
background_dump_dest	 string	 /u01/app/oracle/diag/rdbms/buy/sales/trace
core_dump_dest			 string  /u01/app/oracle/diag/rdbms/buy/sales/cdump
max_dump_file_size		 string	 unlimited
shadow_core_dump		 string	 partial
user_dump_dest			 string	 /u01/app/oracle/diag/rdbms/buy/sales/trace
           
[[email protected] ~]$ cd /u01/app/oracle/diag/rdbms/buy/sales/trace
[[email protected] /u01/app/oracle/diag/rdbms/buy/sales/trace]$ ls -lrt
-rw-r----- 1 oracle oinstall  92610 Apr 20 11:33 sales_ora_4691.trc
           

簡單介紹

dump

塊中的内容

從這裡開始

dump

Start dump data blocks tsn: 4 file#:4 minblk 268 maxblk 268
Block dump from cache:
Dump of buffer cache at level 4 for tsn=4 rdba=16777484
Block dump from disk:
buffer tsn: 4 rdba: 0x0100010c (4/268)
scn: 0x0000.0005f8e7 seq: 0x01 flg: 0x06 tail: 0xf8e70601
frmt: 0x02 chkval: 0x85fa type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x00007F2B7FE15A00 to 0x00007F2B7FE17A00
           

下面都是

16

進制數,看不懂也不需要看他

Dump of memory from 0x00007F2B7FE15A00 to 0x00007F2B7FE17A00
7F2B7FE15A00 0000A206 0100010C 0005F8E7 06010000  [................]
7F2B7FE15A10 000085FA 00000002 00003D92 0005E057  [.........=..W...]
7F2B7FE15A20 00000000 00320002 01000108 00130002  [......2.........]
7F2B7FE15A30 0000016D 00C00873 000100CD 00006001  [m...s........`..]
7F2B7FE15A40 0005F629 001E0003 0000017A 00C00A6C  [).......z...l...]
7F2B7FE15A50 001B006B 00002100 0005F8E7 00000000  [k....!..........]
7F2B7FE15A60 00000000 02800100 00000001 04240200  [..............$.]
7F2B7FE15A70 033C0760 00000000 01001064 00000000  [`.<.....d.......]
7F2B7FE15A80 00000000 00001F60 120411F8 121C1210  [....`...........]
7F2B7FE15A90 12341228 124C1240 12641258 127C1270  [([email protected].|.]
           

從這裡開始就是

index segment

真正記錄的東西,注意看

index segment

也是二維結構,兩個字段(col1、col2)也就是

object_id

rowid

header address 139824805796452=0x7f2b7fe15a64
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 1
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 1
kdxconro 512
kdxcofbo 1060=0x424
kdxcofeo 1888=0x760
kdxcoavs 828
kdxlespl 0
kdxlende 0
kdxlenxt 16781412=0x1001064
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8032
row#0[4600] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 03  --第一行
col 1; len 6; (6):  01 00 00 8b 00 30
row#1[4612] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 03
col 1; len 6; (6):  01 00 01 e9 00 30
row#2[4624] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 03
col 1; len 6; (6):  01 00 02 ed 00 01
row#3[4636] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 03
col 1; len 6; (6):  01 00 03 d3 00 1c
           

我們建立

index

的時候是建在了

object_id

上,是以就會按照

object_id

進行排序,但是

object_id

是有重複的,按照

object_id

排序之後就按

rowid

進行排序了,如果

object_id

是唯一的就不用

rowid

我們來驗證

col1

記錄的是什麼

col 0; len 2; (2):  c1 03  --第一行
           

下面是表中的資料

Index的原理

object_id

排序了,第一行是

2

,看一下

2

16

進制數是多少

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

DUMP(2,16)
-----------------
Typ=2 Len=2: c1,3
--Typ2表示number類型,Len2表示占用兩個位元組,c1,3中間的0省略了,也就是說c1,3就是0
           

也可以把

c1 03

轉成

number

類型

SQL> select utl_raw.cast_to_number('c103') from dual;

UTL_RAW.CAST_TO_NUMBER('C103')
------------------------------
			     2
           

tt2

表中一共有

32

object_id

2

的,看

dump

下來的檔案正好是

32

c1 03

SQL> select count(1) from tt2 where object_id = 2;

  COUNT(1)
----------
	32
           
row#0[4600] flag: ------, lock: 0, len=12
col 0; len 2; (2):  c1 03
col 1; len 6; (6):  01 00 00 8b 00 30
--中間省略了....
row#31[1960] flag: ------, lock: 2, len=12
col 0; len 2; (2):  c1 03
col 1; len 6; (6):  01 00 1e ce 00 19
           

上面的實驗就是說明了你在哪個字段上建立了索引,他就把這個字段的值儲存到了

B

樹索引中的

leaf

節點上了,而且這個

B

樹的葉子節點中的值是排好序的,最小的在最左邊,最大的在最右邊

下面看

col 1

存放的是什麼,他是

16

進制數

col 1; len 6; (6):  01 00 00 8b 00 30
           

把第一行的

rowid

拿出來

AAAD2RAAEAAAACLAAw

,這是

64

進制數

Index的原理

要先把十六進制數轉換成二進制數(不足八位的前邊補

01 00 00 8b 00 30
           

轉換成

00000001 00000000 00000000 10001011 00000000 00110000
           
rowid:AAAD2RAAEAAAACLAAw
           

col1

二進制數的前十位就是表示的相對檔案編号對應

rowid

7-9

位(

AAE

再把前十位轉換成十進制數

0000000100

的十進制數是

4

col1

二進制數的

11-32

位表示的是塊編号對應

rowid

的第

10-15

位(

AAAACL

11-32

000000 00000000 10001011

的十進制數是

139

再看

rowid

的結果,查出來的塊編号也是

139

SQL> select dbms_rowid.rowid_block_number('AAAD2RAAEAAAACLAAw') from dual;

DBMS_ROWID.ROWID_BLOCK_NUMBER('AAAD2RAAEAAAACLAAW')
---------------------------------------------------
						139
           

col1

二進制數的

33-

最後表示的就是資料在這個資料塊的哪一行

00000000 00110000

十進制數是

48

rowid

的計算結果,同樣也是

48

SQL> select dbms_rowid.rowid_row_number('AAAD2RAAEAAAACLAAw') from dual;

DBMS_ROWID.ROWID_ROW_NUMBER('AAAD2RAAEAAAACLAAW')
-------------------------------------------------
					       48
           

綜上所述,我們

dump

下來的

index

leaf

col1

記錄的就是

rowid

的後三部分(

rowid

一共有四部分組成),資料檔案位置、在哪個塊上、在資料塊的哪一行上

rowid

的第一個部分是資料段

id

,這個沒有儲存在

leaf

中因為不需要為了節省空間,在中繼資料中能夠找到這個

index

的關聯資訊是以沒有必要在

leaf

中儲存

Index的原理

leaf

中的

col1

就相當于是書的目錄,

col1

就是具體的頁碼,

leaf

存放在哪個字段上建索引那個索引的值和這個值所在行的

rowid

,這個就是索引的原理

Index的原理