zoukankan      html  css  js  c++  java
  • 组合索引leaf 数据存储

    1 Z
    2 X
    3 U
    4 T
    5 G
    6 F
    7 C
    8 B
    9 A
    1 A
    2 B
    3 C
    4 D
    Oracle的索引是以平衡树的方式组织存储的:保存的是索引列的值,以及该行的rowid的一部分(文件号,块号,行号) 
    下面我们通过例子来了解一下:
    
    
    1,create table test(id int,name varchar2(20))
    insert into test values(1,'Z');
    insert into test values(2,'X');
    insert into test values(3,'U');
    insert into test values(4,'T');
    
    insert into test values(5,'G');
    insert into test values(6,'F');
    
    insert into test values(7,'C');
    insert into test values(8,'B');
    insert into test values(9,'A');
    
    insert into test values(1,'Z');
    insert into test values(2,'B');
    insert into test values(3,'C');
    
    insert into test values(4,'D');
    insert into test values(5,'F');
    
    insert into test values(6,'H');
    insert into test values(7,'G');
    
    insert into test values(8,'H');
    insert into test values(8,'I');
    
    begin
    for i in 3..2000 loop
    insert into test values(i,'t'||i);
    end loop;
    end;
    
    2,创建组合索引:
    
    SQL> create index test_idx2 on test(id ,name);
    
    Index created.
    
    3,得到这个index的object_id:
    
    SQL> select object_id  from dba_objects where object_name='TEST_IDX2';
    
     OBJECT_ID
    ----------
         74574
    
    4,将索引dump到trace文件中
    
    alter session set events 'immediate trace name treedump level 74574';
    
    看到结果:有两层,6个叶子节点
    
    ----- begin tree dump
    branch: 0x1000213 16777747 (0: nrow: 6, level: 1)
       leaf: 0x1000214 16777748 (-1: nrow: 372 rrow: 372)
       leaf: 0x1000215 16777749 (0: nrow: 359 rrow: 359)
       leaf: 0x1000216 16777750 (1: nrow: 355 rrow: 355)
       leaf: 0x1000217 16777751 (2: nrow: 342 rrow: 342)
       leaf: 0x1000218 16777752 (3: nrow: 342 rrow: 342)
       leaf: 0x1000219 16777753 (4: nrow: 246 rrow: 246)
    ----- end tree dump
    
    0x1000ca3 :转为为10进制就是16780451
    
    branch 表示的是 branch block ,它后面跟了一个十六进制表示的DBA(data block address),以及用10进制表示的DBA 
    DBA 之后表示在同一层次的相对位置(root 从0开始,branch 以及leaf从 -1开始)  
    nrow  表示块中包含了多少条目(包括delete的条目)  
    rrow  表示块中包含的实际条目(不包括delete的条目)  
    level 表示从该block到leaf的深度(leaf没有 level)
    
    
    这个 branch block 的 level 为1,也就是说 从这个branch block 到 leaf block 的深度为1,根据前面的查询,这个索引的Blevel为1
    
    验证索引的高度:
    
    SQL> select index_name, PREFIX_LENGTH, BLEVEL, LEAF_BLOCKS from user_indexes where index_name='TEST_IDX2';
    
    INDEX_NAME		       PREFIX_LENGTH	 BLEVEL LEAF_BLOCKS
    ------------------------------ ------------- ---------- -----------
    TEST_IDX2					      1 	  6
    可以看到高度为2=BLEVEL+1,leaf block为6
    
    BLEVEL* NUMBER   B*-Tree level: depth of the index from its root block to its leaf blocks. A depth of 0 indicates that the root block and leaf block are the
    
    same.
    
    LEAF_BLOCKS* NUMBER   Number of leaf blocks in the index
    
    
    现在我来验证一下branch:  0x1000213 16777747 (0: nrow: 6, level: 1) 是不是 root block , 我查询这个 branch 的 DBA
    
    
    SQL> select dbms_utility.data_block_address_file('16777747') FILE_ID,
           dbms_utility.data_block_address_block('16777747') BLOCK_ID
      from dual;    2    3  
    
       FILE_ID   BLOCK_ID
    ---------- ----------
    	 4	  531
    
    
    Btree 索引的 root block总是segment header+1,所以我查询该索引的段头  
      
    SQL> select header_file,header_block from dba_segments where segment_name='TEST_IDX2';
    
    HEADER_FILE HEADER_BLOCK
    ----------- ------------
    	  4	     530
    
    证明branch:  0x1000213 16777747 (0: nrow: 6, level: 1)就是root块,其实 treedump第一个 branch block 就是 root block
    
    
    ######################################################################################
    到此时为止,已经从dump信息得出了索引的高度和第一个branch block就是root block的结论    #
                                                                                         #
                                                                                         #
    ######################################################################################
    ----- begin tree dump
    branch: 0x1000213 16777747 (0: nrow: 6, level: 1)
       leaf: 0x1000214 16777748 (-1: nrow: 372 rrow: 372)
       leaf: 0x1000215 16777749 (0: nrow: 359 rrow: 359)
       leaf: 0x1000216 16777750 (1: nrow: 355 rrow: 355)
       leaf: 0x1000217 16777751 (2: nrow: 342 rrow: 342)
       leaf: 0x1000218 16777752 (3: nrow: 342 rrow: 342)
       leaf: 0x1000219 16777753 (4: nrow: 246 rrow: 246)
    ----- end tree dump
     
    
    
    Oracle 中提供了dbms_utility来求的这个地址对应的文件号和块号(传入的参数是十进制的那个值).
     leaf: 0x1000214 16777748 (-1: nrow: 372 rrow: 372)
    
    查看这个leaf block对应的文件号和块号
    SQL> select dbms_utility.data_block_address_file(16777748)fno,
    dbms_utility.data_block_address_block(16777748) bkno from dual;  2  
    
           FNO	 BKNO
    ---------- ----------
    	 4	  532
    
    得到的是第4号文件的第532块
    
    SQL> select file_id,block_id,blocks from dba_extents where segment_name='TEST_IDX2';
    
       FILE_ID   BLOCK_ID	  BLOCKS
    ---------- ---------- ----------
    	 4	  528	       8
    	 4	  536	       8
    
    
    ##################################################################################
    这里得出了leaf 块存放的数据文件号和对应的块                                      #
    ##################################################################################
    
    5,将索引数据dump出来,dump 4号文件的532块,alter system dump datafile 4 block 532
    
    row#0[8018] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 02
    col 1; len 1; (1):  5a
    col 2; len 6; (6):  01 00 02 0e 00 00
    row#1[8004] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 02
    col 1; len 1; (1):  5a
    col 2; len 6; (6):  01 00 02 0e 00 09
    row#2[7990] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 03
    col 1; len 1; (1):  42
    col 2; len 6; (6):  01 00 02 0e 00 0a
    row#3[7976] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 03
    col 1; len 1; (1):  58
    col 2; len 6; (6):  01 00 02 0e 00 01
    row#4[7962] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 04
    col 1; len 1; (1):  43
    col 2; len 6; (6):  01 00 02 0e 00 0b
    row#5[7948] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 04
    col 1; len 1; (1):  55
    col 2; len 6; (6):  01 00 02 0e 00 02
    row#6[7933] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 04
    col 1; len 2; (2):  74 33
    col 2; len 6; (6):  01 00 02 0f 00 00
    row#7[7919] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 05
    col 1; len 1; (1):  44
    col 2; len 6; (6):  01 00 02 0e 00 0c
    row#8[7905] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 05
    col 1; len 1; (1):  54
    col 2; len 6; (6):  01 00 02 0e 00 03
    row#9[7890] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 05
    col 1; len 2; (2):  74 34
    col 2; len 6; (6):  01 00 02 0f 00 01
    row#10[7876] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 06
    col 1; len 1; (1):  46
    col 2; len 6; (6):  01 00 02 0e 00 0d
    row#11[7862] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 06
    col 1; len 1; (1):  47
    col 2; len 6; (6):  01 00 02 0e 00 04
    row#12[7847] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 06
    col 1; len 2; (2):  74 35
    col 2; len 6; (6):  01 00 02 0f 00 02
    row#13[7833] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 07
    col 1; len 1; (1):  46
    col 2; len 6; (6):  01 00 02 0e 00 05
    row#14[7819] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 07
    col 1; len 1; (1):  48
    col 2; len 6; (6):  01 00 02 0e 00 0e
    row#15[7804] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 07
    col 1; len 2; (2):  74 36
    col 2; len 6; (6):  01 00 02 0f 00 03
    row#16[7790] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 08
    col 1; len 1; (1):  43
    col 2; len 6; (6):  01 00 02 0e 00 06
    row#17[7776] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 08
    col 1; len 1; (1):  47
    col 2; len 6; (6):  01 00 02 0e 00 0f
    row#18[7761] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 08
    col 1; len 2; (2):  74 37
    col 2; len 6; (6):  01 00 02 0f 00 04
    row#19[7747] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 09
    col 1; len 1; (1):  42
    col 2; len 6; (6):  01 00 02 0e 00 07
    row#20[7733] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 09
    col 1; len 1; (1):  48
    col 2; len 6; (6):  01 00 02 0e 00 10
    以前20行为例,
    
    
    col 表示列号,从0开始 那么接下来就是索引的键值 以及 rowid中后12位值
    
    00000001
    
    row#0行号.
    
    col 0第一列(本例中第一列为是id), len 2表示长度是2, (2)表示占了两个字节,c1 02是id的值(这里值是1的16进制表示)的存储表示.
    SQL>  declare
       n number;
     begin
       dbms_stats.convert_raw_value('c102',
                                    n);
       dbms_output.put_line(n);
     end;  2    3    4    5    6    7  
      8  /
    c102 对应的值为1
    
    SQL> declare
      n varchar2(10);
    begin
      dbms_stats.convert_raw_value('41', n);
      dbms_output.put_line(n);
    end;  2    3    4    5    6  
      7  /
    A
    
    PL/SQL procedure successfully completed.
    
    
    
    翻译出来的数据为:
    第一行: 1 Z
    
    第2行:1 Z
    
    第3行:2 B
    
    第4行:2 X
    
    第5行:3 C
    
    第6行:3 U
    
    leaf 块的数据排序时按以上规则排序的。
    1 Z
    2 X
    3 U
    4 T
    5 G
    6 F
    7 C
    8 B
    9 A
    1 A
    2 B
    3 C
    4 D
    Oracle的索引是以平衡树的方式组织存储的:保存的是索引列的值,以及该行的rowid的一部分(文件号,块号,行号) 
    下面我们通过例子来了解一下:
    
    
    
    
    1,create table test(id int,name varchar2(20))
    insert into test values(1,'Z');
    insert into test values(2,'X');
    insert into test values(3,'U');
    insert into test values(4,'T');
    
    
    insert into test values(5,'G');
    insert into test values(6,'F');
    
    
    insert into test values(7,'C');
    insert into test values(8,'B');
    insert into test values(9,'A');
    
    
    insert into test values(1,'Z');
    insert into test values(2,'B');
    insert into test values(3,'C');
    
    
    insert into test values(4,'D');
    insert into test values(5,'F');
    
    
    insert into test values(6,'H');
    insert into test values(7,'G');
    
    
    insert into test values(8,'H');
    insert into test values(8,'I');
    
    
    begin
    for i in 3..2000 loop
    insert into test values(i,'t'||i);
    end loop;
    end;
    
    
    2,创建组合索引:
    
    
    SQL> create index test_idx2 on test(id ,name);
    
    
    Index created.
    
    
    3,得到这个index的object_id:
    
    
    SQL> select object_id  from dba_objects where object_name='TEST_IDX2';
    
    
     OBJECT_ID
    ----------
         74574
    
    
    4,将索引dump到trace文件中
    
    
    alter session set events 'immediate trace name treedump level 74574';
    
    
    看到结果:有两层,6个叶子节点
    
    
    ----- begin tree dump
    branch: 0x1000213 16777747 (0: nrow: 6, level: 1)
       leaf: 0x1000214 16777748 (-1: nrow: 372 rrow: 372)
       leaf: 0x1000215 16777749 (0: nrow: 359 rrow: 359)
       leaf: 0x1000216 16777750 (1: nrow: 355 rrow: 355)
       leaf: 0x1000217 16777751 (2: nrow: 342 rrow: 342)
       leaf: 0x1000218 16777752 (3: nrow: 342 rrow: 342)
       leaf: 0x1000219 16777753 (4: nrow: 246 rrow: 246)
    ----- end tree dump
    
    
    0x1000ca3 :转为为10进制就是16780451
    
    
    branch 表示的是 branch block ,它后面跟了一个十六进制表示的DBA(data block address),以及用10进制表示的DBA 
    DBA 之后表示在同一层次的相对位置(root 从0开始,branch 以及leaf从 -1开始)  
    nrow  表示块中包含了多少条目(包括delete的条目)  
    rrow  表示块中包含的实际条目(不包括delete的条目)  
    level 表示从该block到leaf的深度(leaf没有 level)
    
    
    
    
    这个 branch block 的 level 为1,也就是说 从这个branch block 到 leaf block 的深度为1,根据前面的查询,这个索引的Blevel为1
    
    
    验证索引的高度:
    
    
    SQL> select index_name, PREFIX_LENGTH, BLEVEL, LEAF_BLOCKS from user_indexes where index_name='TEST_IDX2';
    
    
    INDEX_NAME		       PREFIX_LENGTH	 BLEVEL LEAF_BLOCKS
    ------------------------------ ------------- ---------- -----------
    TEST_IDX2					      1 	  6
    可以看到高度为2=BLEVEL+1,leaf block为6
    
    
    BLEVEL* NUMBER   B*-Tree level: depth of the index from its root block to its leaf blocks. A depth of 0 indicates that the root block and leaf block are the
    
    
    same.
    
    
    LEAF_BLOCKS* NUMBER   Number of leaf blocks in the index
    
    
    
    
    现在我来验证一下branch:  0x1000213 16777747 (0: nrow: 6, level: 1) 是不是 root block , 我查询这个 branch 的 DBA
    
    
    
    
    SQL> select dbms_utility.data_block_address_file('16777747') FILE_ID,
           dbms_utility.data_block_address_block('16777747') BLOCK_ID
      from dual;    2    3  
    
    
       FILE_ID   BLOCK_ID
    ---------- ----------
    	 4	  531
    
    
    
    
    Btree 索引的 root block总是segment header+1,所以我查询该索引的段头  
      
    SQL> select header_file,header_block from dba_segments where segment_name='TEST_IDX2';
    
    
    HEADER_FILE HEADER_BLOCK
    ----------- ------------
    	  4	     530
    
    
    证明branch:  0x1000213 16777747 (0: nrow: 6, level: 1)就是root块,其实 treedump第一个 branch block 就是 root block
    
    
    
    
    ######################################################################################
    到此时为止,已经从dump信息得出了索引的高度和第一个branch block就是root block的结论    #
                                                                                         #
                                                                                         #
    ######################################################################################
    ----- begin tree dump
    branch: 0x1000213 16777747 (0: nrow: 6, level: 1)
       leaf: 0x1000214 16777748 (-1: nrow: 372 rrow: 372)
       leaf: 0x1000215 16777749 (0: nrow: 359 rrow: 359)
       leaf: 0x1000216 16777750 (1: nrow: 355 rrow: 355)
       leaf: 0x1000217 16777751 (2: nrow: 342 rrow: 342)
       leaf: 0x1000218 16777752 (3: nrow: 342 rrow: 342)
       leaf: 0x1000219 16777753 (4: nrow: 246 rrow: 246)
    ----- end tree dump
     
    
    
    
    
    Oracle 中提供了dbms_utility来求的这个地址对应的文件号和块号(传入的参数是十进制的那个值).
     leaf: 0x1000214 16777748 (-1: nrow: 372 rrow: 372)
    
    
    查看这个leaf block对应的文件号和块号
    SQL> select dbms_utility.data_block_address_file(16777748)fno,
    dbms_utility.data_block_address_block(16777748) bkno from dual;  2  
    
    
           FNO	 BKNO
    ---------- ----------
    	 4	  532
    
    
    得到的是第4号文件的第532块
    
    
    SQL> select file_id,block_id,blocks from dba_extents where segment_name='TEST_IDX2';
    
    
       FILE_ID   BLOCK_ID	  BLOCKS
    ---------- ---------- ----------
    	 4	  528	       8
    	 4	  536	       8
    
    
    
    
    ##################################################################################
    这里得出了leaf 块存放的数据文件号和对应的块                                      #
    ##################################################################################
    
    
    5,将索引数据dump出来,dump 4号文件的532块,alter system dump datafile 4 block 532
    
    
    row#0[8018] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 02
    col 1; len 1; (1):  5a
    col 2; len 6; (6):  01 00 02 0e 00 00
    row#1[8004] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 02
    col 1; len 1; (1):  5a
    col 2; len 6; (6):  01 00 02 0e 00 09
    row#2[7990] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 03
    col 1; len 1; (1):  42
    col 2; len 6; (6):  01 00 02 0e 00 0a
    row#3[7976] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 03
    col 1; len 1; (1):  58
    col 2; len 6; (6):  01 00 02 0e 00 01
    row#4[7962] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 04
    col 1; len 1; (1):  43
    col 2; len 6; (6):  01 00 02 0e 00 0b
    row#5[7948] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 04
    col 1; len 1; (1):  55
    col 2; len 6; (6):  01 00 02 0e 00 02
    row#6[7933] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 04
    col 1; len 2; (2):  74 33
    col 2; len 6; (6):  01 00 02 0f 00 00
    row#7[7919] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 05
    col 1; len 1; (1):  44
    col 2; len 6; (6):  01 00 02 0e 00 0c
    row#8[7905] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 05
    col 1; len 1; (1):  54
    col 2; len 6; (6):  01 00 02 0e 00 03
    row#9[7890] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 05
    col 1; len 2; (2):  74 34
    col 2; len 6; (6):  01 00 02 0f 00 01
    row#10[7876] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 06
    col 1; len 1; (1):  46
    col 2; len 6; (6):  01 00 02 0e 00 0d
    row#11[7862] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 06
    col 1; len 1; (1):  47
    col 2; len 6; (6):  01 00 02 0e 00 04
    row#12[7847] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 06
    col 1; len 2; (2):  74 35
    col 2; len 6; (6):  01 00 02 0f 00 02
    row#13[7833] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 07
    col 1; len 1; (1):  46
    col 2; len 6; (6):  01 00 02 0e 00 05
    row#14[7819] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 07
    col 1; len 1; (1):  48
    col 2; len 6; (6):  01 00 02 0e 00 0e
    row#15[7804] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 07
    col 1; len 2; (2):  74 36
    col 2; len 6; (6):  01 00 02 0f 00 03
    row#16[7790] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 08
    col 1; len 1; (1):  43
    col 2; len 6; (6):  01 00 02 0e 00 06
    row#17[7776] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 08
    col 1; len 1; (1):  47
    col 2; len 6; (6):  01 00 02 0e 00 0f
    row#18[7761] flag: ------, lock: 0, len=15
    col 0; len 2; (2):  c1 08
    col 1; len 2; (2):  74 37
    col 2; len 6; (6):  01 00 02 0f 00 04
    row#19[7747] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 09
    col 1; len 1; (1):  42
    col 2; len 6; (6):  01 00 02 0e 00 07
    row#20[7733] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 09
    col 1; len 1; (1):  48
    col 2; len 6; (6):  01 00 02 0e 00 10
    以前20行为例,
    
    
    
    
    col 表示列号,从0开始 那么接下来就是索引的键值 以及 rowid中后12位值
    
    
    00000001
    
    
    row#0行号.
    
    
    col 0第一列(本例中第一列为是id), len 2表示长度是2, (2)表示占了两个字节,c1 02是id的值(这里值是1的16进制表示)的存储表示.
    SQL>  declare
       n number;
     begin
       dbms_stats.convert_raw_value('c102',
                                    n);
       dbms_output.put_line(n);
     end;  2    3    4    5    6    7  
      8  /
    c102 对应的值为1
    
    
    SQL> declare
      n varchar2(10);
    begin
      dbms_stats.convert_raw_value('41', n);
      dbms_output.put_line(n);
    end;  2    3    4    5    6  
      7  /
    A
    
    
    PL/SQL procedure successfully completed.
    
    
    
    
    
    
    翻译出来的数据为:
    第一行: 1 Z
    
    
    第2行:1 Z
    
    
    第3行:2 B
    
    
    第4行:2 X
    
    
    第5行:3 C
    
    
    第6行:3 U
    
    
    leaf 块的数据排序时按以上规则排序的。
    先引导列,之后是后面的列。
    


    
                                        
    
  • 相关阅读:
    【分享】64K视频合集
    【原译】四种方法统计字符串的行数&执行时间比较
    【原译】自动省略功能的WPF文本框控件
    【笔记】MD5加密
    【原译】在amazon kindle上安装Metasploit
    【笔记】wubi安装ubuntu遇到的问题
    【笔记】贪心算法找零钱(C#实现)
    ubuntu下在java代码中调用c代码
    sql截取字段最后以特定字符隔开的内容语句
    mysql中删除字符串或字段中空格函数
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13352342.html
Copyright © 2011-2022 走看看