在数据库管理与维护中,我们总会遇到一个问题:我们创建的索引是否会被某些SQL语句使用呢?如果创建的某个索引是Unused Indexes,尤其是没有合理规划索引或管理不规范的系统,可能建立了N个索引,有些没有任何SQL会使用。

这些多余的索引其实会带来两个问题:1:浪费存储空间,尤其是大表的索引,浪费的存储空间尤其可观; 2:加重DML操作(UPDATE、INSERT、DELETE)的开销。

一、 ALTER INDEX MONITORING USAGE

ORACLE其实提供了监控索引使用情况的功能。ALTER INDEX <index_name> MONITORING USAGE;

1. 监控单个索引使用情况

创建一个表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 KerryExecution 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 versionStatistics
----------------------------------------------------------1  recursive calls0  db block gets4  consistent gets0  physical reads0  redo size578  bytes sent via SQL*Net to client492  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  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 KerryExecution 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 versionStatistics
----------------------------------------------------------7  recursive calls0  db block gets10  consistent gets0  physical reads0  redo size578  bytes sent via SQL*Net to client492  bytes received via SQL*Net from client2  SQL*Net roundtrips to/from client0  sorts (memory)0  sorts (disk)1  rows processedSQL> 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。

2. 监控所有索引

如果想在系统中监控所有的索引,可以通过下面脚本实现。注意要排除一些系统表的索引、以及LOB indexes。

原因有下面两个:

  • LOB indexes不能修改,否则会报ORA-22864错误(ORA-22864: cannot ALTER or DROP LOB indexes)。
  • ORA-00701: object necessary for warmstarting database cannot be altered
ORA-00701: 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.sqlSELECT'ALTER INDEX '||OWNER||'.'||INDEX_NAME||' MONITORING USAGE;'
FROMDBA_INDEXES
WHEREINDEX_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语句。

col owner heading "Index Owner" format a30
col index_name heading "Index Name" format a30set linesize 95 trimspool on pagesize 80select *
from(select owner, index_namefrom dba_indexes diwheredi.index_type != 'LOB'andowner not in ('SYS', 'SYSMAN', 'SYSTEM', 'MDSYS', 'WMSYS', 'TSMSYS', 'DBSNMP', 'OUTLN')
minus
select index_owner owner, index_name
from dba_constraints dc
whereindex_owner not in ('SYS', 'SYSMAN', 'SYSTEM', 'MDSYS', 'WMSYS', 'TSMSYS', 'DBSNMP', 'OUTLN')
minus
selectp.object_owner owner,p.object_name  index_name
fromstats$snapshot       sn,stats$sql_plan       p,stats$sql_summary    st,stats$sql_plan_usage spu
wherest.sql_id = spu.sql_id
and spu.plan_hash_value = p.plan_hash_value
andst.hash_value = p.plan_hash_value
andsn.snap_id = st.snap_id
and sn.dbid = st.dbid
and sn.instance_number = st.instance_number
andsn.snap_id = spu.snap_id
and sn.dbid = spu.snap_id
and sn.instance_number = spu.instance_number
andsn.snap_id between &begin_snap and &end_snap
andp.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,999break on c1 skip 2
accept idxname char prompt 'Enter Index Name: '
ttitle 'Invocation Counts for index|&idxname'selectto_char(sn.begin_interval_time,'yy-mm-dd hh24')  c1,p.search_columns                                 c2,count(*)                                         c3
fromdba_hist_snapshot  sn,dba_hist_sql_plan   p,dba_hist_sqlstat   st
wherest.sql_id = p.sql_id
andsn.snap_id = st.snap_id
and   p.object_name = '&idxname'
group bybegin_interval_time,search_columns;

参考资料:

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

如何监控ORACLE索引使用与否相关推荐

  1. oracle索引的监控

    最近的研究发现 Oracle 数据库所使用的索引从来没有达到过可用索引数的1/4, 或者其用法与其开始设计的意图不相同.未用的索引浪费空间,而且还会降低 DML 的速度,尤其是 UPDATE 和 IN ...

  2. oracle 索引_分享三个Oracle数据库索引监控脚本,值得收藏

    概述 我们在维护业务系统时,可能会建立很多索引,那么这些索引的使用到底怎么样,是否有些索引一直都没有用到过,那么oracle 是如何监控索引的使用状况,是否可以清除它们? 监控索引 一般有两种方式: ...

  3. 如何监控oracle的索引是否使用

    很多软件开发过程中,没有注意合理规划索引,造成一个表上有N多个索引,为后续的维护和优化带来麻烦.因此有时候需要监控已有的索引是否在使用,oracle提供了监控索引是否使用的工具,很简单,简要介绍一下. ...

  4. oracle 索引监控

    oracle 索引监控 即使是一个初期设计非常优秀的数据库系统,在持续运行一段时间后,由于数据量的累加,数据库对象的变化,甚至是业务方面的改变,多可能会对数据库的性能带来影响.所以一个持续.健康的数据 ...

  5. lepus监控oracle数据库_实用脚本一键监控oracle数据库索引使用状况

    概述 我们在维护业务系统时,可能会建立很多索引,那么这些索引的使用到底怎么样,是否有些索引一直都没有用到过,那么oracle 是如何监控索引的使用状况,是否可以清除它们? 监控索引 一般有两种方式: ...

  6. 查看oracle索引状态,oracle监控索引的使用情况

    1.使用monitor index来监控索引使用 监控单个索引使用情况:alter index monitoring usage; 关闭监控: alter index nomonitoring usa ...

  7. 监控Oracle性能的SQL

    监控Oracle性能的SQL 1. 监控事例的等待     select event,sum(decode(wait_Time,0,0,1)) "Prev",    sum(dec ...

  8. 监控Oracle数据库

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

  9. 监控Oracle数据库的常用shell脚本

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

最新文章

  1. 是什么岗位_文案策划的岗位职责是什么?
  2. Python 2.4 递归函数
  3. GitHub火热!程序员小哥不得不知的所有定律法则(附项目链接)
  4. 如何查看python安装位置图_怎么查看python安装路径
  5. Linux下安装.bundle后缀的程序
  6. Redis 注册为 widows 服务
  7. AndroidStudio Gradle自定义属性xmlns无法识别
  8. 华中科技大学应用高等工程数学_专业解析【第152期】| 机械电子工程课程设置及研究方向...
  9. php动态获取函数参数
  10. Web前端新手必看的7种技术,从菜鸟到高级开发的蜕变!
  11. 转)TNS协议--翻译自《The Oracle Hackers Handbook》
  12. linux队列运行任务查看,Linux work queue工作队列小结与使用
  13. ExtJS应用架构设计(二)
  14. Teststand 中用labview 读写station options属性
  15. PS-给文字填充图片纹理
  16. 综合素质计算机的知识考点,综合素质考点知识
  17. 域名是否被微信、qq拦截?怎么查询
  18. 报考条件及择校建议:法硕(非法学)与法硕(法学)
  19. 判别IP地址的网络类别
  20. 35岁后,不是你被淘汰,而是你没有发现你的价值 | 如何发现35岁后的价值?

热门文章

  1. CorelDraw常用操作
  2. 荣耀8 android8.0 2018,荣耀这次很良心! 荣耀8全系可以升级安卓8.0
  3. iPhone/iTouch开发技术介绍
  4. 按键精灵安卓版访问php接,按键安卓版网络访问之 图片处理,FTP,HTTP 实现
  5. 计算机系统结构--复习(Part 1)
  6. linux网卡e1000下载,Linux E1000网卡驱动分析
  7. 十年测试经验悟出的测试心得
  8. SolidWorks 如何在曲面上获取与基准线相交的分割线
  9. 大学英语听说教程光盘及读写光盘使用技巧(原创)
  10. JavaScript案例 全选 获取下拉框选中的值