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

Posted linbobo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle索引碎片检查及定期重建常用表的索引相关的知识,希望对你有一定的参考价值。

转载地址:http://www.cnblogs.com/zhaoguan_wang/p/5169821.html

背景说明:

       今天查阅书籍时,偶然间发现“在对某个索引行执行删除操作时,只是为该行增加了一个删除标记,这个索引行并不会释放它的存储空间,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

 

备注:

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

以上是关于Oracle索引碎片检查及定期重建常用表的索引的主要内容,如果未能解决你的问题,请参考以下文章

ORACLE关于索引是否需要定期重建争论的整理

oracle中重建索引

oracle, 表索引占用空间非常大, 15g以上了, 重建索引后所用空间缩减为原来不到1/5, 这是啥原因?

SQL Server通过整理索引碎片和重建索引提高速度

用于重建和重新索引碎片索引的脚本?

Oracle11G_索引