背景说明:

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

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

alter index IDX_tkk29_PARTICIPANT rebuild;

alter index IDX_tkk29_ACTUALPARTICIPANT rebuild;

analyze index IDX_tkk29_PARTICIPANT validate structure;

重建索引:

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索引碎片检查及定期重建常用表的索引的更多相关文章

  1. oracle删除当前用户以及当前用户所有表、索引等操作

    ORACLE删除当前用户下所有的表的方法 如果有删除用户的权限,则可以: drop user user_name cascade; 加了cascade就可以把用户连带的数据全部删掉.删除后再创建该用户 ...

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

    ORACLE数据库中的索引到底要不要定期重建呢? 如果不需要定期重建,那么理由是什么? 如果需要定期重建,那么理由又是什么?另外,如果需要定期重建,那么满足那些条件的索引才需要重建呢?关于这个问题,网 ...

  3. Oracle查询索引碎片及数据表空间使用情况

    --检查索引碎片情况,只能对单个表进行分析. --需要注意块的大小.索引的pctfree的值的大小.rowid的长度的不同,根据不同的情况修改相应的值 select index_name, c.NMB ...

  4. Oracle索引以及索引碎片

    索引,可以增加查询速度,若没有索引,每次查询都必须是全表查询.例如,搜索某个记录时(如name="gdpuzxs")时,需要全表扫描一下,因为不知道有多少个name="g ...

  5. SQLServer中重建聚集索引之后会影响到非聚集索引的索引碎片吗

    本文出处:http://www.cnblogs.com/wy123/p/7650215.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...

  6. SQL Server 索引碎片产生原理重建索引和重新组织索引

    数据库存储本身是无序的,建立了聚集索引,会按照聚集索引物理顺序存入硬盘.既键值的逻辑顺序决定了表中相应行的物理顺序 多数情况下,数据库读取频率远高于写入频率,索引的存在 为了读取速度牺牲写入速度 页 ...

  7. [笔记整理]SQL Server 索引碎片 和 重建索引

    铺垫知识点: 数据库存储本身是无序的,建立了聚集索引,会按照聚集索引物理顺序存入硬盘.既键值的逻辑顺序决定了表中相应行的物理顺序 多数情况下,数据库读取频率远高于写入频率,索引的存在 为了读取速度牺牲 ...

  8. 转: SQL Server索引的维护 - 索引碎片、填充因子

    转:http://www.cnblogs.com/kissdodog/archive/2013/06/14/3135412.html 实际上,索引的维护主要包括以下两个方面: 页拆分 碎片 这两个问题 ...

  9. SQL Server索引的维护 - 索引碎片、填充因子 <第三篇>

    实际上,索引的维护主要包括以下两个方面: 页拆分 碎片 这两个问题都和页密度有关,虽然两者的表现形式在本质上有所区别,但是故障排除工具是一样的,因为处理是相同的. 对于非常小的表(比64KB小得多), ...

随机推荐

  1. 随感一:android handler传值更改ui

    handler+looper传值更改activity的UI 博客开了一段时间,一直想写点自己的学习经验及体会,等着以后长时间不用再要用到的时候直接拿过来上手.想了想,之前用到handler, 看了几篇 ...

  2. hash表C语言实现

    算法参考<算法导论>第11章散列表.采用链地址法解决冲突. #include <stdio.h> #include <stdlib.h> #include < ...

  3. FFMpeg的码率控制

    mediaxyz是一位研究ffmpeg有三年的高人了,这几天一直在折腾ffmpeg中的x264,就是不知道该如何控制码率,主要是参数太多,也不知道该如何设置,在google上search了一下,这方面 ...

  4. 服务器列表里找不到OracleOraDb10g_home1TNSListener

    先安装的ORACLE DB,后配置的数据库,TNSNAMES.ORA, LISTENER.ORA配置完毕,客户端连接不上TNS服务器,发现服务列表里没有OracleOraDb10g_home1TNSL ...

  5. 发布网站时报错:未能将文件xxx复制到xxx,问题处理

    发布时报错提示: 错误 1 未能将文件 UpLoad\images\73CDC40ECCA44550BA8201D2AC187A46.jpg 复制到 obj\Debug\Package\Package ...

  6. 安卓--Toast

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWind ...

  7. LeetCode 102

    方法一:(迭代) /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * ...

  8. Git 的深入理解与GitHub托管服务(转)

    源代码管理系统(SCM)与版本控制   版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统.   本地版本控制系统   许多人习惯用复制整个项目目录的方式来保存不同的版本,或许还会 ...

  9. Intellj IDEA Java随笔

    敲击sout+Tab会出现:System.out.println(); int(-2147483648, 2147483647) 当一个方法类型不是void时,那么我们不仅要考虑它正确时的返回值,错误 ...

  10. SE Homework 1 —An Error Impressed Me

    在对两个对象进行比较.判断是否相等时,直接用 == 放在两个对象中间,例如下面的代码: Infor i1 = new Infor(111,"AA"); Infor i2 = new ...