如何监控ORACLE索引使用与否
在数据库管理与维护中,我们总会遇到一个问题:我们创建的索引是否会被某些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索引使用与否的更多相关文章
- oracle索引监控
目的:监控oracle索引的有效性,看索引有没有被使用.然后根据监控结果删除或者调整索引. 步骤: 1.监控指定索引 命令: alter index 索引名 monitoring usage; 如 ...
- ORACLE索引监控的简单使用
--ORACLE索引监控的简单使用-------------------------2013/11/20 说明: 应用程序在开发时,可能会建立众多索引,但是这些索引的使用到底怎么样,是否有些索 ...
- Oracle监控用户索引使用情况,删除无用索引
监控当前业务用户索引 一段时间后查询从未被使用的索引,删除无用索引 停止监控索引 1. 监控当前用户所有索引 得到监控所有索引的语句: select 'alter index ' || index_n ...
- [转]Oracle 索引质量分析
http://blog.csdn.net/leshami/article/details/23687137 索引质量的高低对数据库整体性能有着直接的影响.良好高质量的索引使得数据库性能得以数量级别的提 ...
- 8个DBA最常用的监控Oracle数据库的常用shell脚本
本文介绍了8个常用的监控数据shell脚本.首先回顾了一些DBA常用的Unix命令,以及解释了如何通过Unix Cron来定时执行DBA脚本.网上也有好多类似的文章,但基本上都不能正常运行,花点时间重 ...
- 如何监控Oracle
介绍了DBA每天在监控Oracle数据库方面的职责,讲述了如何通过shell脚本来完成这些重复的监控工作.本文首先回顾了一些DBA常用的Unix命令,以及解释了如何通过Unix Cron来定时执行DB ...
- 使用Zabbix监控Oracle数据库
Orabbix介绍 监控Oracle数据库我们需要安装第三方提供的Zabbix插件,我们先测试比较有名的Orabbix,http://www.smartmarmot.com/product/orabb ...
- Oracle索引重建
一.前言 Oracle建议对于索引深度超过4级以及已删除的索引条目至少占有现有索引条目总数的20% 这2种情形下需要重建索引.有人持不同观点,就是强烈建议不要定期重建索引.索引重建是一个争论不休被不断 ...
- Oracle索引梳理系列(九)- 浅谈聚簇因子对索引使用的影响及优化方法
版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...
随机推荐
- .NET中的逆变协变
MSDN上的说法: 协变和逆变都是术语,前者指能够使用比原始指定的派生类型的派生程度更小(不太具体的)的类型,后者指能够使用比原始指定的派生类型的派生程度更大(更具体的)的类型----------(注 ...
- ElasticSearch 5学习(4)——简单搜索笔记
空搜索: GET /_search hits: total 总数 hits 前10条数据 hits 数组中的每个结果都包含_index._type和文档的_id字段,被加入到_source字段中这意味 ...
- .NET Core全新的配置管理[共9篇]
提到“配置”二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置信息定义在这两 ...
- 增强学习(三)----- MDP的动态规划解法
上一篇我们已经说到了,增强学习的目的就是求解马尔可夫决策过程(MDP)的最优策略,使其在任意初始状态下,都能获得最大的Vπ值.(本文不考虑非马尔可夫环境和不完全可观测马尔可夫决策过程(POMDP)中的 ...
- PHP实现删除数组中的特定元素
方法1: <?php $arr1 = array(1,3, 5,7,8); $key = array_search(3, $arr1); if ($key !== false) array_sp ...
- Index
我主要在研究.NET/C# 实现 PC IMERP 和 Android IMERP ,目的在解决企业通信中遇到的各类自动化问题 分布式缓存框架: Microsoft Velocity:微软自家分布 ...
- UITableViewCell单元格的删除、插入、移动
UITableViewDelegate的方法 设置编辑模式中得cell的编辑样式(删除或插入) - (UITableViewCellEditingStyle)tableView:( ...
- 【WCF】如何将WCF部署到远程服务器
一.前言 最近需要将自己写的WCF服务部署到远程服务器上,也就是公网上.宿主是IIS,在配置成功之前遇到了很多问题,问题如下: 1. WCF该怎么宿主在IIS上,为何会出现 400 Bad ...
- bzoj4518--斜率优化DP
设x[i]为第i天走的路程,s为路程总和,则: ans=[(s/m-x[1])^2+(s/m-x[2])^2+(s/m-x[3])^2+...+(s/m-x[m])^2]*m =[(s-x[1]*m) ...
- Windows程序设计_19_测试Windows应用程序加载函数
/* 本程序测试自定义的WinMainCRTStartup函数 */ #define STRICT #define WIN32_LEAN_AND_MEAN #include <windows.h ...