dump bitmap(位图索引)内部研究

      一直对位图索引印象都不深刻,通过dump内容,逐步就清晰了。可以看到索引在这种数据结构下,当频繁的修改数据,会造成严重的enq: TX - row lock contention等待事件。

SQL> create table t_bitmap(a number, b number);

SQL>  insert into t_bitmap select rownum,mod(rownum,5) from all_objects where rownum < 21;

SQL> commit;

SQL> create bitmap index i_t_bitmap on t_bitmap(b);

SQL> exec show_space('I_T_BITMAP',user,'INDEX');

Unformatted Blocks .....................              0

FS1 Blocks (0-25)  .....................               0

FS2 Blocks (25-50) .....................              1

FS3 Blocks (50-75) .....................              0

FS4 Blocks (75-100).....................              0

Full Blocks        .....................               0

Total Blocks............................              8

Total Bytes.............................         65,536

Total MBytes............................              0

Unused Blocks...........................              4

Unused Bytes............................         32,768

Last Used Ext FileId....................              6

Last Used Ext BlockId...................        122,737

Last Used Block.........................              4

SQL> alter system dump datafile 6 block 122740;

内容如下:

Block header dump:  0x0181df74

 Object id on Block? Y

 seg/obj: 0x1799b  csc: 0x959.da1b85c8  itc: 2  flg: E  typ: 2 - INDEX

     brn: 0  bdba: 0x181df71 ver: 0x01 opc: 0

     inc: 0  exflg: 0

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc

0x01   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000

0x02   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0959.da1b85c8

Leaf block dump

===============

header address 151923300=0x90e2a64

kdxcolev 0

KDXCOLEV Flags = - - -

kdxcolok 0

kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y

kdxconco 4

kdxcosdc 0

kdxconro 5

kdxcofbo 46=0x2e

kdxcofeo 7918=0x1eee

kdxcoavs 7872

kdxlespl 0

kdxlende 0

kdxlenxt 0=0x0

kdxleprv 0=0x0

kdxledsz 0

kdxlebksz 8036

row#0[8013] flag: ------, lock: 0, len=23

col 0; len 1; (1):  80    ------代表索引数字0

col 1; len 6; (6):  01 81 df 6e 00 00  ---rowid 起点的block和行号

col 2; len 6; (6):  01 81 df 6e 00 17 ---rowid 结束的block和行号,注意17 = 16+7 = 23

col 3; len 4; (4):  ca 10 42 08  

十六进制转换为二进制:select pkg_number_trans.f_hex_to_bin('ca104208')from dual;--来自于http://blog.csdn.net/guogang83/article/details/8002014

--- 1100 1010(首字节不表示rowid信息) 000100000100001000001000凡是从起点到结束点内的1表示该值存在,这里有一个必须要注意的问题是,这样转化后的位置并不是真实的物理位置,在每个字节内部bit还要颠倒一下顺序(计算机写bit的时候是从低位到高位),首字节不表示位置信息,也就是说上面的应该转换为 000010000100001000010000,发现正好每5位中存在一个值为0的记录。

根据0181df6e找到是哪个数据块:

select pkg_number_trans.f_hex_to_dec('0181df6e') decnum  from dual;
DECNUM
--------------------------------------------------------------------------------
25288558
select dbms_utility.data_block_address_file(25288558) "file", dbms_utility.data_block_address_block(25288558) "block"  from dual;
      file      block
---------- ----------
         6     122734

row#1[7990] flag: ------, lock: 0, len=23

col 0; len 2; (2):  c1 02    ------代表索引数字1

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 0f

col 3; len 3; (3):  c9 21 84

row#2[7966] flag: ------, lock: 0, len=24

col 0; len 2; (2):  c1 03  ------代表索引数字2

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 42 08 01

row#3[7942] flag: ------, lock: 0, len=24

col 0; len 2; (2):  c1 04  ------代表索引数字3

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 84 10 02

row#4[7918] flag: ------, lock: 0, len=24

col 0; len 2; (2):  c1 05  ------代表索引数字4

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 08 21 04

----- end of leaf block dump -----

SQL> delete from t_bitmap where a = 19;

SQL> alter system dump datafile 6 block 122740;

row#0[8013] flag: ------, lock: 0, len=23

col 0; len 1; (1):  80

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 10 42 08

row#1[7990] flag: ------, lock: 0, len=23

col 0; len 2; (2):  c1 02

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 0f

col 3; len 3; (3):  c9 21 84

row#2[7966] flag: ------, lock: 0, len=24

col 0; len 2; (2):  c1 03

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 42 08 01

row#3[7942] flag: ------, lock: 0, len=24

col 0; len 2; (2):  c1 04

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 84 10 02

row#4[7894] flag: ------, lock: 2, len=24

col 0; len 2; (2):  c1 05

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 08 21 00

同上可以得:

select pkg_number_trans.f_hex_to_bin('ca082100')from dual;

11001010  00001000  0010000100000000,去掉第一个字节后颠倒顺序:

00000000  00100001 00001000

SQL> delete from t_bitmap where b=4;

SQL> alter system dump datafile 6 block 122740;

row#0[8013] flag: ------, lock: 0, len=23

col 0; len 1; (1):  80

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 10 42 08

row#1[7990] flag: ------, lock: 0, len=23

col 0; len 2; (2):  c1 02

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 0f

col 3; len 3; (3):  c9 21 84

row#2[7966] flag: ------, lock: 0, len=24

col 0; len 2; (2):  c1 03

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 42 08 01

row#3[7942] flag: ------, lock: 0, len=24

col 0; len 2; (2):  c1 04

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 84 10 02

row#4[7894] flag: ---D--, lock: 2, len=24   --标记为删除

col 0; len 2; (2):  c1 05

col 1; len 6; (6):  01 81 df 6e 00 00

col 2; len 6; (6):  01 81 df 6e 00 17

col 3; len 4; (4):  ca 08 21 00

 

dump 多个数据块语法:alter system dump datafile 8 block min 74496 block max 74499;

附:根据dump的的rowid信息找到是哪个块上的数据。

select idx_rowid('0181e0480037') from dual;
 
IDX_ROWID('0181E0480037')
--------------------------------------------------------------------------------
File# = 6, Block# = 122952, Row# = 55

CREATE OR REPLACE TYPE type_str_agg AS OBJECT
(
  total VARCHAR2(4000),

  STATIC FUNCTION odciaggregateinitialize(sctx IN OUT type_str_agg)
    RETURN NUMBER,

  MEMBER FUNCTION odciaggregateiterate
  (
    SELF  IN OUT type_str_agg,
    VALUE IN VARCHAR2
  ) RETURN NUMBER,

  MEMBER FUNCTION odciaggregateterminate
  (
    SELF        IN type_str_agg,
    returnvalue OUT VARCHAR2,
    flags       IN NUMBER
  ) RETURN NUMBER,

  MEMBER FUNCTION odciaggregatemerge
  (
    SELF IN OUT type_str_agg,
    ctx2 IN type_str_agg
  ) RETURN NUMBER
)
/

CREATE OR REPLACE TYPE BODY type_str_agg IS

  STATIC FUNCTION odciaggregateinitialize(sctx IN OUT type_str_agg)
    RETURN NUMBER IS
  BEGIN
    sctx := type_str_agg(NULL);
    RETURN odciconst.success;
  END;

  MEMBER FUNCTION odciaggregateiterate
  (
    SELF  IN OUT type_str_agg,
    VALUE IN VARCHAR2
  ) RETURN NUMBER IS
  BEGIN
    SELF.total := SELF.total || VALUE;
    RETURN odciconst.success;
  END;

  MEMBER FUNCTION odciaggregateterminate
  (
    SELF        IN type_str_agg,
    returnvalue OUT VARCHAR2,
    flags       IN NUMBER
  ) RETURN NUMBER IS
  BEGIN
    returnvalue := SELF.total;
    RETURN odciconst.success;
  END;

  MEMBER FUNCTION odciaggregatemerge
  (
    SELF IN OUT type_str_agg,
    ctx2 IN type_str_agg
  ) RETURN NUMBER IS
  BEGIN
    SELF.total := SELF.total || ctx2.total;
    RETURN odciconst.success;
  END;

END;
/

CREATE OR REPLACE FUNCTION f_stragg(p_input VARCHAR2) RETURN VARCHAR2
  PARALLEL_ENABLE
  AGGREGATE USING type_str_agg;
/

CREATE OR REPLACE PACKAGE pkg_number_trans IS
  FUNCTION f_bin_to_dec(p_str IN VARCHAR2) RETURN VARCHAR2;
  FUNCTION f_hex_to_bin(p_str IN VARCHAR2) RETURN VARCHAR2;
END pkg_number_trans;
/

CREATE OR REPLACE PACKAGE BODY pkg_number_trans IS
  FUNCTION f_bin_to_dec(p_str IN VARCHAR2) RETURN VARCHAR2 IS
    ----------------------------------------------------------------------------------------------------------------------
    -- 对象名称: f_bin_to_dec
    -- 对象描述: 二进制转换十进制
    -- 输入参数: p_str 二进制字符串
    -- 返回结果: 十进制字符串
    -- 测试用例: SELECT pkg_number_trans.f_bin_to_dec('11110001010') FROM dual;
    ----------------------------------------------------------------------------------------------------------------------
    v_return  VARCHAR2(4000);
  BEGIN
    SELECT SUM(data1) INTO v_return
      FROM (SELECT substr(p_str, rownum, 1) * power(2, length(p_str) - rownum) data1
              FROM dual
            CONNECT BY rownum <= length(p_str));
    RETURN v_return;
  EXCEPTION
    WHEN OTHERS THEN
      RETURN NULL;
  END f_bin_to_dec;

  FUNCTION f_hex_to_bin(p_str IN VARCHAR2) RETURN VARCHAR2 IS
    ----------------------------------------------------------------------------------------------------------------------
    -- 对象名称: f_dec_to_oct
    -- 对象描述: 十六进制转换二进制
    -- 输入参数: p_str 十六进制字符串
    -- 返回结果: 二进制字符串
    -- 测试用例: SELECT pkg_number_trans.f_hex_to_oct('78A') FROM dual;
    ----------------------------------------------------------------------------------------------------------------------
    v_return VARCHAR2(4000);
  BEGIN
    SELECT to_char(f_stragg(data1)) INTO v_return
      FROM (SELECT (CASE upper(substr(p_str, rownum, 1))
                     WHEN '0' THEN '0000'
                     WHEN '1' THEN '0001'
                     WHEN '2' THEN '0010'
                     WHEN '3' THEN '0011'
                     WHEN '4' THEN '0100'
                     WHEN '5' THEN '0101'
                     WHEN '6' THEN '0110'
                     WHEN '7' THEN '0111'
                     WHEN '8' THEN '1000'
                     WHEN '9' THEN '1001'
                     WHEN 'A' THEN '1010'
                     WHEN 'B' THEN '1011'
                     WHEN 'C' THEN '1100'
                     WHEN 'D' THEN '1101'
                     WHEN 'E' THEN '1110'
                     WHEN 'F' THEN '1111'
                   END) data1
              FROM dual
            CONNECT BY rownum <= length(p_str));
    RETURN v_return;
  EXCEPTION
    WHEN OTHERS THEN
      RETURN NULL;
  END f_hex_to_bin;
END pkg_number_trans;
/

create or replace function idx_rowid(p_in_str in varchar2) return varchar2 is
  Result varchar2(1000);
  bin_str                                               varchar2(4000);
  file_str                                              varchar2(100);
  block_str                                             varchar2(1000);
  row_str                                               varchar2(1000);
  obj_str                                               varchar2(1000);
begin
  bin_str := pkg_number_trans.f_hex_to_bin(replace(p_in_str,' ',''));

  row_str := substr(bin_str,length(bin_str)-15,16);
  block_str := substr(bin_str,length(bin_str)-37,22);
  file_str := substr(bin_str,length(bin_str)-47,10);
 
  if length(bin_str)=80 then
    obj_str := substr(bin_str,length(bin_str)-79,32);
  end if;

  row_str := pkg_number_trans.f_bin_to_dec(row_str);
  block_str := pkg_number_trans.f_bin_to_dec(block_str);
  file_str := pkg_number_trans.f_bin_to_dec(file_str);
 
  if length(bin_str)=80 then
    obj_str :=  pkg_number_trans.f_bin_to_dec(obj_str);
  end if;

  if length(bin_str)=80 then
    Result := 'File# = '||file_str||', Block# = '||block_str||', Row# = '||row_str||', Obj# = '||obj_str;
  else
    Result := 'File# = '||file_str||', Block# = '||block_str||', Row# = '||row_str;
  end if;
  return(Result);
end idx_rowid;
/

你可能感兴趣的:(oracle内部原理)