• Oracle索引碎片检查及定期重建常用表的索引


    背景说明:

           今天查阅书籍时,偶然间发现“在对某个索引行执行删除操作时,只是为该行增加了一个删除标记,这个索引行并不会释放它的存储空间,Insert产生的新的索引行也不能被插入到该位置。索引列的修改过程其实是将对应的列值删除,然后再插入新的列值(与数据行本身的修改是不一致的,这也正是我们尽量不使用修改频繁的列来创建索引的原因)。所以,无论是插入、修改、删除,都需要消耗存储空间,增大B-Tree索引结构的深度,影响数据的查询速度。尤其是删除和修改,不仅造成了存储空间的浪费,而且增加了扫描索引块的数量”,这就是所谓的索引碎片问题,建议定期对经常使用的表执行检查和重建索引操作。

    问题重现:

          经测试,收集统计信息等操作,无法释放索引删除块所占用的存储空间。

    analyze table tkk29 compute statistics;

    select t.index_name, t.distinct_keys, t.num_rows, t.sample_size, t.last_analyzed
          , t.blevel, t.leaf_blocks, t.*
    from user_indexes t
    where t.table_name = upper('tkk29');

    tkk2901

    delete from tkk29
    where mod(trunc((sysdate-createddate) * 24 * 60), 2) = 0;

    analyze table tkk29 compute statistics;

    analyze index IDX_tkk29_PARTICIPANT validate structure;

    select t.name, t.blocks, t.lf_rows, t.del_lf_rows, t.lf_rows - t.del_lf_rows as lf_rows_used
           , to_char((t.del_lf_rows/t.lf_rows) * 100, '999.999') as ratio, t.*
    from index_stats t

    image

    image

    alter index IDX_tkk29_PARTICIPANT rebuild;

    alter index IDX_tkk29_ACTUALPARTICIPANT rebuild;

    analyze index IDX_tkk29_PARTICIPANT validate structure;

    image

    image

    重建索引:

    CREATE OR REPLACE TYPE strsplit_type AS TABLE OF VARCHAR2(32676);
    
    CREATE OR REPLACE FUNCTION strsplit(p_value VARCHAR2, p_split VARCHAR2 := ',')
     --usage: select * from table(strsplit('1,2,3,4,5'))
     RETURN strsplit_type
    PIPELINED IS
     v_idx       INTEGER;
     v_str       VARCHAR2(500);
     v_strs_last VARCHAR2(4000) := p_value;
    BEGIN
     LOOP
      v_idx := instr(v_strs_last, p_split);
      EXIT WHEN v_idx = 0;
      v_str       := substr(v_strs_last, 1, v_idx - 1);
      v_strs_last := substr(v_strs_last, v_idx + 1);
      PIPE ROW(v_str);
     END LOOP;
     PIPE ROW(v_strs_last);
     RETURN;
    END strsplit;
    CREATE OR REPLACE PROCEDURE UP_CHECK_TO_REBUILD_INDEX
    (
           tbNames varchar
    )
    IS
        sqlstr VARCHAR2(100);
        idx_ratio INT;
    BEGIN       
        --DECLARE sqlstr VARCHAR2(100);
        --        idx_ratio INT;
        BEGIN
            FOR idx IN (SELECT t.index_name FROM user_indexes t 
                        WHERE t.index_type = 'NORMAL' AND t.status = 'VALID' AND t.temporary = 'N' AND t.leaf_blocks > 100
                            AND t.table_name IN (SELECT UPPER(TRIM(COLUMN_VALUE)) from table(strsplit(tbNames))) --//('TKK29')
                        ORDER BY t.table_name, t.index_name
                       )
            LOOP
                DBMS_OUTPUT.put_LINE(idx.index_name || ' ANALYZE START ' || TO_CHAR(SYSDATE, 'yyyy-MM-dd hh24:mi:ss'));
                sqlstr := 'ANALYZE INDEX ' || idx.Index_Name || ' VALIDATE STRUCTURE';
                EXECUTE IMMEDIATE sqlstr;
                
                SELECT TRUNC((t.del_lf_rows/t.lf_rows) * 100) INTO idx_ratio 
                FROM index_stats t WHERE t.name=idx.index_name AND ROWNUM=1;
                
                IF (idx_ratio >= 15) THEN
                   DBMS_OUTPUT.put_line('    REINDEX ' || TO_CHAR(SYSDATE, 'yyyy-MM-dd hh24:mi:ss') || ' ratio: ' || idx_ratio);
                   sqlstr := 'ALTER INDEX ' || idx.index_name || ' REBUILD';
                   EXECUTE IMMEDIATE sqlstr;
                END IF;
            END LOOP;
        END;
    END UP_CHECK_TO_REBUILD_INDEX;
    
    
    
    SQL>exec UP_CHECK_TO_REBUILD_INDEX('TKK29, muser');
    
    begin
           UP_CHECK_TO_REBUILD_INDEX('TKK29, muser');
    end;

    PK_MUSER ANALYZE START 2016-01-29 17:49:19
    IDX_TKK29_ACTIVITYINSTANCEID ANALYZE START 2016-01-29 17:49:19
        REBUILD INDEX START 2016-01-29 17:49:20 ratio: 50
    IDX_TKK29_ACTUALPARTICIPANT ANALYZE START 2016-01-29 17:49:22
    IDX_TKK29_COMPLETEDDATE ANALYZE START 2016-01-29 17:49:22
        REBUILD INDEX START 2016-01-29 17:49:22 ratio: 36
    IDX_TKK29_PARTICIPANT ANALYZE START 2016-01-29 17:49:23
    IDX_TKK29_PROCESSINSTANCEID ANALYZE START 2016-01-29 17:49:23
        REBUILD INDEX START 2016-01-29 17:49:24 ratio: 50
    IDX_TKK29_STATEDDATE ANALYZE START 2016-01-29 17:49:25
        REBUILD INDEX START 2016-01-29 17:49:25 ratio: 33
    PK_TKK29 ANALYZE START 2016-01-29 17:49:27
        REBUILD INDEX START 2016-01-29 17:49:27 ratio: 50

    备注:

        真实场景请考虑索引列的修改、数据删除的概率,结合表的数据量大小等多种因素制定合理的维护计划;另外,分区表的不同分区应该有不同的策略。

  • 相关阅读:
    Jmeter的几种参数化方式
    selenium实现原理
    python问题
    跨域问题的解决方案
    jquery的ajax的语法
    给JavaScript 对象添加方法
    循环遍历对象的属性
    Function专题 以及js的预解析理解
    如何理解javascript中类和对象这两个概念?
    封装原生ajax
  • 原文地址:https://www.cnblogs.com/zhaoguan_wang/p/5169821.html
Copyright © 2020-2023  润新知