天天看点

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的原理