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

    Oracle的索引是以平衡树的方式组织存储的:保存的是索引列的值,以及该行的rowid的一部分(文件号,块号,行号)
    下面我们通过例子来了解一下:


    1,create table test(id int,name varchar2(20))
    insert into test values(1,'A');
    insert into test values(2,'B');

    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
    ----------
         74564

    4,将索引dump到trace文件中

    alter session set events 'immediate trace name treedump level 74564';

    看到结果:有两层,6个叶子节点

    ----- begin tree dump
    branch: 0x1000ca3 16780451 (0: nrow: 6, level: 1)
       leaf: 0x1000ca4 16780452 (-1: nrow: 369 rrow: 369)
       leaf: 0x1000ca5 16780453 (0: nrow: 359 rrow: 359)
       leaf: 0x1000ca6 16780454 (1: nrow: 354 rrow: 354)
       leaf: 0x1000ca7 16780455 (2: nrow: 342 rrow: 342)
       leaf: 0x1000ca8 16780456 (3: nrow: 342 rrow: 342)
       leaf: 0x1000ca9 16780457 (4: nrow: 234 rrow: 234)
    ----- 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

    可以看到高度为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: 0x1000ca3 16780451 (0: nrow: 6, level: 1) 是不是 root block , 我查询这个 branch 的 DBA


    SQL> select dbms_utility.data_block_address_file('16780451') FILE_ID,
           dbms_utility.data_block_address_block('16780451') BLOCK_ID
      from dual;   2    3 

       FILE_ID   BLOCK_ID
    ---------- ----------
      4  3235


    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     3234

    证明branch: 0x1000ca3 16780451 (0: nrow: 6, level: 1) 就是root块,其实 treedump第一个 branch block 就是 root block


    ######################################################################################
    到此时为止,已经从dump信息得出了索引的高度和第一个branch block就是root block的结论    #
                                                                                         #
                                                                                         #
    ######################################################################################
    ----- begin tree dump
    branch: 0x1000ca3 16780451 (0: nrow: 6, level: 1)
       leaf: 0x1000ca4 16780452 (-1: nrow: 369 rrow: 369)
       leaf: 0x1000ca5 16780453 (0: nrow: 359 rrow: 359)
       leaf: 0x1000ca6 16780454 (1: nrow: 354 rrow: 354)
       leaf: 0x1000ca7 16780455 (2: nrow: 342 rrow: 342)
       leaf: 0x1000ca8 16780456 (3: nrow: 342 rrow: 342)
       leaf: 0x1000ca9 16780457 (4: nrow: 234 rrow: 234)
    ----- end tree dump


    Oracle 中提供了dbms_utility来求的这个地址对应的文件号和块号(传入的参数是十进制的那个值).
     leaf: 0x1000ca4 16780452 (-1: nrow: 369 rrow: 369)

    查看这个leaf block对应的文件号和块号

    SQL> select dbms_utility.data_block_address_file(16780452)fno,
    dbms_utility.data_block_address_block(16780452) bkno from dual;  2 

           FNO  BKNO
    ---------- ----------
      4  3236


    得到的是第4号文件的第3236块

    SQL> select file_id,block_id,blocks from dba_extents where segment_name='TEST_IDX2';

       FILE_ID   BLOCK_ID   BLOCKS
    ---------- ---------- ----------
      4  3232        8
      4  3240        8


    ##################################################################################
    这里得出了leaf 块存放的数据文件号和对应的块                                      #
    ##################################################################################

    5,将索引数据dump出来,dump 4号文件的3236块,alter system dump datafile 4 block 3236

    row#0[8018] flag: ------, lock: 0, len=14
    col 0; len 2; (2):  c1 02
    col 1; len 1; (1):  41
    col 2; len 6; (6):  01 00 0c 8f 00 00
    row#1[8004] 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 0c 8f 00 01
    row#2[7989] 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 0c 8f 00 02
    row#3[7974] flag: ------, lock: 0, len=15

    以前三行为例,


    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.


    41对应的值为A

    也就是锁组合索引的键值存储格式是存储在2列上


    col 2; len 6; (6):  01 00 0c 8f 00 00 这个就包含了rowid的信息

    col 2的rowid,01 00 0c 8f 00 00是rowid的一部分值,也是16进制的.,先要转换成2进制的,再通过各个位数代表的意义计算文件号,块号和和行号。

    01 00 0c 8f 00 00 先转换为2进制:(注意前面先补足0)
    10000000000001100100011110000000000000000

    00000001 00000000 00001100 10001111 00000000 00000000


    然后串起来之后前10位 00000001 00 表示文件号,=4

    然后是接下来的22位 000000 00000000 00001100表示块号=3215

    最后面的的16位表示行号=0

    SQL> select rowid,
           id,
           dbms_rowid.rowid_relative_fno('AAASM/AAEAAAAyPAAA') fno,
           dbms_rowid.rowid_block_number('AAASM/AAEAAAAyPAAA') bkno,
           dbms_rowid.rowid_row_number('AAASM/AAEAAAAyPAAA') rno
      from test
     where id = 1;  2    3    4    5    6    7 

    ROWID      ID      FNO       BKNO    RNO
    ------------------ ---------- ---------- ---------- ----------
    AAASM/AAEAAAAyPAAA     1        4       3215      0

    上面的sql得到是4号文件3125块0行.证明索引里保存的为rowid的一部分信息。


    总结:dump信息包括了索引的高度,leaf block指向数据块的地址(包括数据文件好和块号),记录了一部分的rowid信息

  • 相关阅读:
    android RecyclerView smoothScrollToPosition 每次都能滚动到顶部
    android eventbus四种线程模型
    android代码设置主题无效setTheme
    Word备忘录
    Markdown基本语法
    游戏常用术语
    字体格式
    Excel备忘录
    离线方式快速安装python模块以及相关依赖模块
    kube-proxy
  • 原文地址:https://www.cnblogs.com/zhaoyangjian724/p/3797981.html
Copyright © 2011-2022 走看看