在数据库管理与维护中,我们总会遇到一个问题:我们创建的索引是否会被某些SQL语句使用呢?换个通俗表达方式:我创建的索引是否是未使用的索引(unused Indexes),是否有价值呢?如果创建的某个索引是Unused Indexes,尤其是没有合理规划索引的系统或那些管理控制不规范的系统。有可能建立了N个索引,其实有些索引都是没有任何SQL会使用,那么此时这些多余的索引其实会带来两个问题:1:浪费存储空间,尤其是大表的索引,浪费的存储空间尤其可观; 2:加重DML操作(UPDATE、INSERT、DELETE)的开销。

ORACLE其实提供了监控索引使用情况的功能。ALTER INDEX <index_name> MONITORING USAGE; 我们下面来测试验证一下吧。

创建一个表TEST作为实验测试验证的样例

CREATE TABLE TEST

(

    ID    NUMBER(10),

    NAME  VARCHAR2(32)

);

CREATE INDEX IDX_TEST_ID ON TEST(ID);

 

INSERT INTO TEST 

SELECT 1001, 'Kerry' FROM DUAL UNION ALL

SELECT 1002, 'Ken'   FROM DUAL UNION ALL

SELECT 1003, 'Jimmy' FROM DUAL UNION ALL

SELECT 1004, 'Jack'  FROM DUAL;

COMMIT;

 

execute dbms_stats.gather_table_stats(ownname => 'ETL', tabname =>'TEST', estimate_percent =>DBMS_STATS.AUTO_SAMPLE_SIZE, method_opt => 'FOR ALL COLUMNS SIZE AUTO');

启用对索引IDX_TEST_ID的监控

ALTER INDEX IDX_TEST_ID MONITORING USAGE;

此时观察V$OBJECT_USAGE表数据的变化,如下所示,MONITORIN字段值变为YES,表示索引IDX_TEST_ID已经被置于监控状态。USED字段为NO表示暂时没有SQL使用该索引

SQL> COL INDEX_NAME FOR A20       

SQL> COL TABLE_NAME FOR A10

SQL> COL MONITORING FOR A10

SQL> COL USED FOR A10

SQL> COL START_MONITORING FOR A20

SQL> COL END_MONITORING FOR A20

SQL> SELECT * FROM V$OBJECT_USAGE;

 

INDEX_NAME   TABLE_NAME MONITORING USED  START_MONITORING     END_MONITORING

------------ ---------- ---------- ---- -------------------- ----------------

IDX_TEST_ID   TEST       YES        NO   11/28/2015 14:57:41

此时我们执行下面SQL,因为此时使用全表扫描,那么索引IDX_TEST_ID依然没有被使用,此时可以查看V$OBJECT_USAGE进行验证。

SQL> SET AUTOTRACE ON;

SQL> SELECT * FROM TEST WHERE ID =1001;

 

        ID NAME

---------- --------------------------------

      1001 Kerry

 

 

Execution Plan

----------------------------------------------------------

----------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost  |

----------------------------------------------------------

|   0 | SELECT STATEMENT  |      |     1 |     9 |     2 |

|   1 |  TABLE ACCESS FULL| TEST |     1 |     9 |     2 |

----------------------------------------------------------

Note

-----

   - 'PLAN_TABLE' is old version

 

 

Statistics

----------------------------------------------------------

          1  recursive calls

          0  db block gets

          4  consistent gets

          0  physical reads

          0  redo size

        578  bytes sent via SQL*Net to client

        492  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          1  rows processed

如下所示,此时索引IDX_TEST_ID依然没有被使用。

我们使用索引提示强制下面SQL使用索引IDX_TEST_ID

SELECT /*+ INDEX(TEST IDX_TEST_ID) */* FROM TEST WHERE ID =1001;

此时你就会发现USED的值变为了YES了。

ALTER INDEX IDX_TEST_ID NOMONITORING USAGE;

执行上面命令后,在V$OBJECT_USAGE表中,就会更新表TEST记录的END_MONITORING、MONITORING的值。

如果你又启用监控索引使用情况,那么系统会更新START_MONITORING、END_MONITORING字段的值(END_MONITORING的值更新为NULL)。如果删除表

TEST,此时你会发现V$OBJECT_USAGE对象中关于表TEST的记录也不见了。

注意:SELECT * FROM V$OBJECT_USAGE; 只能查看当前用户下被监控的索引信息。即使sys、system用户也不能查看其它用户的信息。

在测试过程中有个小疑问,就是在准备测试环境时,如果不对表收集统计信息的话,那么即使SQL走全表扫描,你依然发现V$OBJECT_USAGE中索引被标记使用了。如下所示

DROP TABLE TEST PURGE;

 

CREATE TABLE TEST

(

    ID    NUMBER(10),

    NAME  VARCHAR2(32)

);

CREATE INDEX IDX_TEST_ID ON TEST(ID);

 

INSERT INTO TEST 

SELECT 1001, 'Kerry' FROM DUAL UNION ALL

SELECT 1002, 'Ken'   FROM DUAL UNION ALL

SELECT 1003, 'Jimmy' FROM DUAL UNION ALL

SELECT 1004, 'Jack'  FROM DUAL;

COMMIT;

 

ALTER INDEX IDX_TEST_ID MONITORING USAGE;

SQL> SET AUTOTRACE ON;

SQL> SELECT *  FROM TEST WHERE ID =1001;

 

        ID NAME

---------- --------------------------------

      1001 Kerry

 

 

Execution Plan

----------------------------------------------------------

----------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost  |

----------------------------------------------------------

|   0 | SELECT STATEMENT  |      |     1 |    31 |     2 |

|   1 |  TABLE ACCESS FULL| TEST |     1 |    31 |     2 |

----------------------------------------------------------

Note

-----

   - 'PLAN_TABLE' is old version

 

 

Statistics

----------------------------------------------------------

          7  recursive calls

          0  db block gets

         10  consistent gets

          0  physical reads

          0  redo size

        578  bytes sent via SQL*Net to client

        492  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

SQL> SELECT * FROM V$OBJECT_USAGE;

 

INDEX_NAME   TABLE_NAME MONITORING USED   START_MONITORING    END_MONITORING

------------ ---------- ---------- ------  -----------    -------------------

IDX_TEST_ID   TEST       YES        YES   11/28/2015 15:11:46

那么为什么呢? 猜测是在解析生成执行计划时,用到了索引的一些信息,导致V$OBJECT_USAGE表中的字段USED被标记为YES。

如果我们想在系统中监控所有的索引,那么我们可以通过下面脚本实现监控数据库所有的索引。注意我们要排除一些系统表的索引、以及LOB indexes。原因有下面两个:

1:LOB indexes不能修改,否则会报ORA-22864错误(ORA-22864: cannot ALTER or DROP LOB indexes)。

2:ORA-00701: object necessary for warmstarting database cannot be altered

ORA-00701: object necessary for warmstarting database cannot be altered

00701. 00000 - "object necessary for warmstarting database cannot be altered"

*Cause: Attempt to alter or drop a database object (table, cluster, or

index) which are needed for warmstarting the database.

*Action: None.

SET PAGES 999;

SET HEADING OFF;

SPOOL run_monitor.sql

 

SELECT

   'ALTER INDEX '||OWNER||'.'||INDEX_NAME||' MONITORING USAGE;'

FROM

   DBA_INDEXES

WHERE

   INDEX_TYPE != 'LOB' AND OWNER NOT IN  ('SYS', 'SYSMAN', 'SYSTEM', 'MDSYS', 'WMSYS', 'TSMSYS', 'DBSNMP', 'OUTLN')

;

 

SPOOL OFF;

 

@run_monitor.sql

此时使用下面脚本就能查出那些索引是未使用索引,当然监控索引时长非常重要,太短的话有可能导致查询出来的数据有问题,一般建议监控一周后即可,OLAP系统则需要适当延长监控的时间。

 

SELECT I.TABLE_OWNER,

       T.TABLE_NAME,

       I.INDEX_NAME,

       U.USED,

       U.START_MONITORING,

       U.END_MONITORING

FROM USER_TABLES T

INNER JOIN USER_INDEXES I

ON T.TABLE_NAME = I.TABLE_NAME

INNER JOIN V$OBJECT_USAGE U

ON U.TABLE_NAME    = I.TABLE_NAME

AND I.INDEX_NAME   = U.INDEX_NAME

WHERE I.TABLE_OWNER=SYS_CONTEXT('USERENV','CURRENT_USER')

另外,博客Oracle - Find unused Indexes中介绍了一个查找没有使用索引的SQL语句。如下所示statspack_unused_indexes.sql

col owner heading "Index Owner" format a30

col index_name heading "Index Name" format a30

 

set linesize 95 trimspool on pagesize 80

 

select * 

from

   (select 

      owner, 

      index_name

   from 

      dba_indexes di

   where

      di.index_type != 'LOB'

   and

      owner not in ('SYS', 'SYSMAN', 'SYSTEM', 'MDSYS', 'WMSYS', 'TSMSYS', 'DBSNMP', 'OUTLN')

minus

select 

   index_owner owner, 

   index_name

from 

   dba_constraints dc

where

   index_owner not in ('SYS', 'SYSMAN', 'SYSTEM', 'MDSYS', 'WMSYS', 'TSMSYS', 'DBSNMP', 'OUTLN')

minus

select

   p.object_owner owner,

   p.object_name  index_name

from

   stats$snapshot       sn,

   stats$sql_plan       p,

   stats$sql_summary    st,

   stats$sql_plan_usage spu

where

   st.sql_id = spu.sql_id 

and 

   spu.plan_hash_value = p.plan_hash_value

and

   st.hash_value = p.plan_hash_value

and

   sn.snap_id = st.snap_id 

and 

   sn.dbid = st.dbid 

and 

   sn.instance_number = st.instance_number

and

   sn.snap_id = spu.snap_id

and 

   sn.dbid = spu.snap_id 

and 

   sn.instance_number = spu.instance_number

and

   sn.snap_id between &begin_snap and &end_snap

and

   p.object_type = 'INDEX'

)

where owner not in ('SYS', 'SYSMAN', 'SYSTEM', 'MDSYS', 'WMSYS', 'TSMSYS', 'DBSNMP', 'OUTLN')

order by 1, 2

/

这里是另一个脚本用来跟踪未使用的索引并展示给所有索引的调用计数。最重要的是,这个脚本显示了多列索引引用的列(这个脚本执行时间较长,资源开销较大。)

col c1 heading 'Begin|Interval|time' format a20

col c2 heading 'Search Columns'      format 999

col c3 heading 'Invocation|Count'    format 99,999,999

 

 

break on c1 skip 2

 

accept idxname char prompt 'Enter Index Name: '

 

ttitle 'Invocation Counts for index|&idxname'

 

select

   to_char(sn.begin_interval_time,'yy-mm-dd hh24')  c1,

   p.search_columns                                 c2,

   count(*)                                         c3

from

   dba_hist_snapshot  sn,

   dba_hist_sql_plan   p,

   dba_hist_sqlstat   st

where

   st.sql_id = p.sql_id

and

   sn.snap_id = st.snap_id   

and   

   p.object_name = '&idxname'

group by

   begin_interval_time,search_columns;

参考资料:

http://www.dba-oracle.com/oracle_tips_unused_indexes.htm

如何监控ORACLE索引使用与否的更多相关文章

  1. oracle索引监控

    目的:监控oracle索引的有效性,看索引有没有被使用.然后根据监控结果删除或者调整索引. 步骤: 1.监控指定索引 命令: alter index  索引名 monitoring usage;  如 ...

  2. ORACLE索引监控的简单使用

    --ORACLE索引监控的简单使用-------------------------2013/11/20 说明:     应用程序在开发时,可能会建立众多索引,但是这些索引的使用到底怎么样,是否有些索 ...

  3. Oracle监控用户索引使用情况,删除无用索引

    监控当前业务用户索引 一段时间后查询从未被使用的索引,删除无用索引 停止监控索引 1. 监控当前用户所有索引 得到监控所有索引的语句: select 'alter index ' || index_n ...

  4. [转]Oracle 索引质量分析

    http://blog.csdn.net/leshami/article/details/23687137 索引质量的高低对数据库整体性能有着直接的影响.良好高质量的索引使得数据库性能得以数量级别的提 ...

  5. 8个DBA最常用的监控Oracle数据库的常用shell脚本

    本文介绍了8个常用的监控数据shell脚本.首先回顾了一些DBA常用的Unix命令,以及解释了如何通过Unix Cron来定时执行DBA脚本.网上也有好多类似的文章,但基本上都不能正常运行,花点时间重 ...

  6. 如何监控Oracle

    介绍了DBA每天在监控Oracle数据库方面的职责,讲述了如何通过shell脚本来完成这些重复的监控工作.本文首先回顾了一些DBA常用的Unix命令,以及解释了如何通过Unix Cron来定时执行DB ...

  7. 使用Zabbix监控Oracle数据库

    Orabbix介绍 监控Oracle数据库我们需要安装第三方提供的Zabbix插件,我们先测试比较有名的Orabbix,http://www.smartmarmot.com/product/orabb ...

  8. Oracle索引重建

    一.前言 Oracle建议对于索引深度超过4级以及已删除的索引条目至少占有现有索引条目总数的20% 这2种情形下需要重建索引.有人持不同观点,就是强烈建议不要定期重建索引.索引重建是一个争论不休被不断 ...

  9. Oracle索引梳理系列(九)- 浅谈聚簇因子对索引使用的影响及优化方法

    版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...

随机推荐

  1. .NET 基础 一步步 一幕幕[运算符、占位符、转义符]

      运算符.占位符.转义符 好吧,在五局全胜之后,终于升到了三个钻,距离一个星星还有一大段距离,忽然想起来今天的博客还没写,果断坑队友,来写博客了....感觉以后还是每天更新一篇比较好.要不晚上就该熬 ...

  2. Docker私有仓库搭建

    # 环境 系统 Linux 3.10.0-123.9.3.el7.x86_64 CentOS 7.0.1406 (Core) Docker 1.12.0, build 8eab29e 1.获取镜像 私 ...

  3. xp搭建IIS出现HTTP 500错误-2147467259 (0x80004005)

    安装IIS后访问localhost页面, 提示The remote procedure call failed and did not execute,再刷新变为:-2147467259 (0x800 ...

  4. 反向代理与 Real-IP 和 X-Forwarded-For

    开篇语:开涛新作<亿级流量网站架构核心技术>出版计划公布以来,博文视点遭受到一波又一波读者询问面世时间的DDos攻击.面对亿级流量的热情,感激之余,我们也很庆幸——这部作品质量的确过硬,不 ...

  5. Eclipse 使用技巧

    1.Eclipse 格式化代码时不换行与自动换行 Eclipse 推荐的编码风格默认是80列换行.每次用Eclipse自带的Ctrl+shift+f格式化代码时,如果原来的一行代码大于80列,Ecli ...

  6. 偶遇this之坑

    前言 在写一个懒加载插件时,遇到一个坑,就是this的指向问题,我想这种情况大部分人都会遇到,就写下来,新手也有个参考. 事件 有些页面图片比较多,但用户还不一定会全看,这样的话,全部去加载这些图片, ...

  7. 中文分词之结巴分词~~~附使用场景+demo(net)

    常用技能(更新ing):http://www.cnblogs.com/dunitian/p/4822808.html#skill 技能总纲(更新ing):http://www.cnblogs.com/ ...

  8. ASP.NET Core中的依赖注入(2):依赖注入(DI)

    IoC主要体现了这样一种设计思想:通过将一组通用流程的控制从应用转移到框架之中以实现对流程的复用,同时采用"好莱坞原则"是应用程序以被动的方式实现对流程的定制.我们可以采用若干设计 ...

  9. YYModel 源码解读(二)之NSObject+YYModel.h (5)

    好了,之前的博文中详细的解释了一些辅助的类和辅助的函数,接下来就是使用它们来实现酷炫功能的时候,正所谓磨刀不误砍柴工啊 我们先把总的功能罗列出来 1. json转字典              + ( ...

  10. Rafy 框架 - 插件级别的扩展点

    本章说明如何使用额外的插件(如客户化插件)对另一插件(如产品插件)进行扩展.   使用场景 在 产品线工程 中,项目的研发分为领域工程和应用工程.这个过程中会需要对领域工程中的内容进行大量的扩展.   ...