背景说明:

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

    一.外部存储的目录 1.2.3之前是/sdcard 2.4.3之前是在/mnt/sdcard 3.4.3之后是在/storage/sdcard 二.读写读写外部存储 1.直接写路径 File file ...

  2. Best Coder Round#25 1003 树的非递归访问

    虽然官方解释是这题目里的树看作无向无环图,从答案来看还是在“以1作为根节点”这一前提下进行的,这棵树搭建好以后,从叶节点开始访问,一直推到根节点即可——很像动态规划的“自底向上”. 但这棵树的搭建堪忧 ...

  3. Excel常用操作

    [对Excel工作表,按某一列数据进行排序] 选中这些数据,在菜单栏上点"数据 - 排序",在弹出的窗口中的主要关键字里选择这一列,按升序或降序,那么其它的数据也会跟着它一一对应变 ...

  4. 深入理解JavaScript系列:试着谈谈闭包

    闭包可能是JavaScript里最被人神乎其神的一个概念,世间万物皆凡夫俗子,你觉着他神奇是因为你根本没有了解,所有的事物当你了解透彻后就不会有这种不明觉厉的错觉了.哈哈哈,上来又是一顿哲学普及. 下 ...

  5. eclipse新建文件模板默认charset=ISO-8859-1解决

    在安装目录下找到eclipse.ini用记事本打开,添加一行-Dfile.encoding=utf-8,就ok了. 这是应为模板中使用了encoding这个变量

  6. H3C汇聚层交换机认证在线人数展示系统之需求说明和功能点说明

    一.需求 (一)每五分钟查询一次交换机的连接情况: (二)每2.5分钟更新每栋楼的连接情况. 二.功能点 序号 功能点说明 待定 完成 未完成 完成时间 预计用时(min) 实际用时(min) 备注 ...

  7. iOS内置音频

    Predefined soundsThere are some predefined system sounds, for the system sound ID in the range 1000 ...

  8. Azure自动化实例: 复制blog用于备份

    在Azure 自动化:使用PowerShell Credential连接到Azure, 之后, 我在项目中遇到了实现blog备份的任务, 现将其作为一个实例写下来: 1. 首先,创建自动化帐户, 在资 ...

  9. sass的安装与使用

    一.SASS简介:SASS是一种使CSS的开发,变得简单和可维护开发工具. 二.安装和使用 2.1 SASS的安装:  安装sass之前首先需要安装ruby,ruby的安装可以直接在百度搜索安装,安装 ...

  10. day05 java JDBC案例—Android小白的学习笔记

    1.要从键盘录入用户名与密码我们需要使用Scanner类完成操作 2.接收到用户名与密码后,我们需要调用jdbc程序根据用户名与密码查询数据库 User.java package com.superg ...