BITMAP索引异常增大问题


在一个数据库中发现了一个异常增大的对象,经检查改对象为BITMAP索引。

    在数据库中执行下面的脚本,发现了一个异常增大的对象:

    SQL> SELECT SEGMENT_NAME, SEGMENT_TYPE, SUM(BYTES)/1024/1024/1024 G
    2 FROM USER_SEGMENTS
    3 GROUP BY SEGMENT_NAME, SEGMENT_TYPE
    4 HAVING SUM(BYTES)/1024/1024/1024 > 15;

    SEGMENT_NAME SEGMENT_TYPE G
    ------------------------------ ------------------ ----------
    TU_ORD_ORDER_ZJ_K_CODE INDEX 16.7539215

    检查该对象的详细信息:

    SQL> SELECT INDEX_NAME, INDEX_TYPE FROM USER_INDEXES
    2 WHERE INDEX_NAME = ’TU_ORD_ORDER_ZJ_K_CODE’;

    INDEX_NAME INDEX_TYPE
    ------------------------------ ---------------------------
    TU_ORD_ORDER_ZJ_K_CODE FUNCTION-BASED BITMAP

    这个对象是一个基于函数的BITMAP索引。一般来说,BITMAP索引的大小要远远小于普通索引,而这里索引的大小达到了16G,远远超过表本身的大小,这里肯定存在问题。通过对DBMS_SPACE包中SPACE_USAGE过程的封装,检查这个对象的空间使用情况:

    SQL> create or replace procedure p_space_usage (p_segment_name in varchar2,
    2 p_segment_type in varchar2 default ’TABLE’,
    3 p_segment_owner in varchar2 default user,
    4 p_partition_name in varchar2 default ’’) as
    5 v_unformatted_blocks number;
    6 v_unformatted_bytes number;
    7 v_fs1_blocks number;
    8 v_fs1_bytes number;
    9 v_fs2_blocks number;
    10 v_fs2_bytes number;
    11 v_fs3_blocks number;
    12 v_fs3_bytes number;
    13 v_fs4_blocks number;
    14 v_fs4_bytes number;
    15 v_full_blocks number;
    16 v_full_bytes number;
    17 begin
    18 dbms_space.space_usage(upper(p_segment_owner), upper(p_segment_name), upper(p_segment_type), v_unformatted_blocks,
    19 v_unformatted_bytes, v_fs1_blocks, v_fs1_bytes, v_fs2_blocks, v_fs2_bytes, v_fs3_blocks, v_fs3_bytes,
    20 v_fs4_blocks, v_fs4_bytes, v_full_blocks, v_full_bytes, upper(p_partition_name));
    21
    22 dbms_output.put_line(’unformatted_blocks is ’ || v_unformatted_blocks);
    23 dbms_output.put_line(’unformatted_bytes is ’ || v_unformatted_bytes);
    24 dbms_output.put_line(’fs1_blocks is ’ || v_fs1_blocks);
    25 dbms_output.put_line(’fs1_bytes is ’ || v_fs1_bytes);
    26 dbms_output.put_line(’fs2_blocks is ’ || v_fs2_blocks);
    27 dbms_output.put_line(’fs2_bytes is ’ || v_fs2_bytes);
    28 dbms_output.put_line(’fs3_blocks is ’ || v_fs3_blocks);
    29 dbms_output.put_line(’fs3_bytes is ’ || v_fs3_bytes);
    30 dbms_output.put_line(’fs4_blocks is ’ || v_fs4_blocks);
    31 dbms_output.put_line(’fs4_bytes is ’ || v_fs4_bytes);
    32 dbms_output.put_line(’full_blocks is ’ || v_full_blocks);
    33 dbms_output.put_line(’full_bytes is ’ || v_full_bytes);
    34 end;
    35 /

    Procedure created.

    SQL> SET SERVEROUT ON SIZE 10000
    SQL> EXEC P_SPACE_USAGE(’TU_ORD_ORDER_ZJ_K_CODE’, ’INDEX’, ’NDMAIN’)
    unformatted_blocks is 2038268

    unformatted_bytes is 16697491456
    fs1_blocks is 0
    fs1_bytes is 0
    fs2_blocks is 139652
    fs2_bytes is 1144029184
    fs3_blocks is 0
    fs3_bytes is 0
    fs4_blocks is 0
    fs4_bytes is 0
    full_blocks is 13365
    full_bytes is 109486080

    PL/SQL procedure successfully completed.

    问题已经很显然了,这个基于函数的BITMAP索引包含了大量的unformatted blocks,造成大量空间的浪费,而实际上索引所需要的空间并没有这么大。

    检查METALINK,发现Oracle处理ASSM表空间的BITMAP索引存在空间浪费的bug,详细bug描述参考:Bug No. 2915226。

    Oracle给出了一个例子来重现这个bug:

    SQL> SELECT TABLESPACE_NAME, SEGMENT_SPACE_MANAGEMENT
    2 FROM DBA_TABLESPACES
    3 WHERE TABLESPACE_NAME = ’USERS’;

    TABLESPACE_NAME SEGMEN
    ------------------------------ ------
    USERS AUTO

    SQL> CREATE TABLE T (ID NUMBER NOT NULL, BITMAP_COL NUMBER NOT NULL);

    表已创建。

    SQL> INSERT INTO T SELECT ROWNUM, MOD(ROWNUM, 2) FROM DBA_OBJECTS;

    已创建31016行。

    SQL> CREATE BITMAP INDEX IND_B_T_BIT ON T(BITMAP_COL) TABLESPACE USERS;

    索引已创建。

    SQL> BEGIN
    2 FOR I IN REVERSE 1..1000 LOOP
    3 UPDATE T SET BITMAP_COL = 1
    4 WHERE BITMAP_COL = 0 AND ID = I;
    5 END LOOP;
    6 END;
    7 /

    PL/SQL 过程已成功完成。

    SQL> SET SERVEROUT ON SIZE 1000000
    SQL> EXEC P_SPACE_USAGE(’IND_B_T_BIT’, ’INDEX’)
    unformatted_blocks is 93536
    unformatted_bytes is 766246912
    fs1_blocks is 0
    fs1_bytes is 0
    fs2_blocks is 8211
    fs2_bytes is 67264512
    fs3_blocks is 0
    fs3_bytes is 0
    fs4_blocks is 0
    fs4_bytes is 0
    full_blocks is 18
    full_bytes is 147456

    PL/SQL 过程已成功完成。

    这个结果和这里碰到的问题几乎完全一致,只不过这个例子是人为构造bug的产生,而数据库中则是由于正常修改在某些情况下触发了这个bug,检查当前的表空间信息:

    SQL> SELECT INDEX_NAME, TABLESPACE_NAME FROM USER_INDEXES
    2 WHERE INDEX_NAME = ’TU_ORD_ORDER_ZJ_K_CODE’;

    INDEX_NAME TABLESPACE_NAME
    ------------------------------ ------------------------------
    TU_ORD_ORDER_ZJ_K_CODE INDX

    SQL> SELECT SEGMENT_SPACE_MANAGEMENT FROM USER_TABLESPACES
    2 WHERE TABLESPACE_NAME = ’INDX’;

    SEGMEN
    ------
    AUTO

    这个Bug在10.1.0.2被修正,对于9.2.0.2以上的版本,可以直接下载编号为2915226的patch来解决这个问题

本文作者:
« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3