【DB笔试面试562】在Oracle中,如何监控索引的使用状况?

  • 2019 年 10 月 10 日
  • 筆記

题目部分

在Oracle中,如何监控索引的使用状况?

答案部分

在开发应用程序时,可能会建立很多索引,那么这些索引的使用到底怎么样,是否有些索引一直都没有用到过,在这种情况下就需要对这些索引进行监控,以便确定它们的使用情况,并为是否可以清除它们给出依据。

监控索引有两种方式:

1、直接监控索引的使用情况

(1)设置所要监控的索引:ALTER INDEX IDX_T_XX MONITORING USAGE;

(2)查看该索引有没有被使用:SELECT * FROM V$OBJECT_USAGE;

(3)关闭监控:ALTER INDEX IDX_T_XX NOMONITORING USAGE;

查询V$OBJECT_USAGE就可以知道数据库对索引的使用情况了。通过一段时间的监控,就可以确定哪些是无用的索引。另外,为了避免使用V$OBJECT_USAGE只能查询到当前用户下索引的监控情况,可以使用如下语句查询数据库中所有被监控索引的使用情况:

 SELECT U.NAME OWNER,          IO.NAME INDEX_NAME,          T.NAME TABLE_NAME,          DECODE(BITAND(I.FLAGS, 65536), 0, 'NO', 'YES') MONITORING,          DECODE(BITAND(OU.FLAGS, 1), 0, 'NO', 'YES') USED,          OU.START_MONITORING START_MONITORING,          OU.END_MONITORING END_MONITORING    FROM SYS.USER$        U,          SYS.OBJ$         IO,          SYS.OBJ$         T,          SYS.IND$         I,          SYS.OBJECT_USAGE OU    WHERE I.OBJ# = OU.OBJ#      AND IO.OBJ# = OU.OBJ#      AND T.OBJ# = I.BO#      AND U.USER# = IO.OWNER#;  

2、通过查看历史的执行计划,分析索引的使用情况

可以从视图DBA_HIST_SQL_PLAN中获取到数据库中所有索引的扫描次数情况,然后根据扫描次数和开发人员沟通是否需要保留索引。

WITH TMP1 AS   (SELECT I.OWNER INDEX_OWNER,           I.TABLE_OWNER,           TABLE_NAME,           INDEX_NAME,           INDEX_TYPE,           (SELECT NB.CREATED              FROM DBA_OBJECTS NB             WHERE NB.OWNER = I.OWNER               AND NB.OBJECT_NAME = I.INDEX_NAME               AND NB.SUBOBJECT_NAME IS NULL               AND NB.OBJECT_TYPE = 'INDEX') CREATED,           (SUM(S.BYTES) / 1024 / 1024) INDEX_MB,          (SELECT COUNT(1)          FROM   DBA_IND_COLUMNS DIC          WHERE  DIC.INDEX_NAME = I.INDEX_NAME          AND    DIC.TABLE_NAME = I.TABLE_NAME          AND    DIC.INDEX_OWNER = I.OWNER) COUNT_INDEX_COLS      FROM DBA_SEGMENTS S, DBA_INDEXES I     WHERE I.INDEX_NAME = S.SEGMENT_NAME       AND I.OWNER = S.OWNER       AND S.OWNER NOT LIKE '%SYS%'     GROUP BY I.OWNER, I.TABLE_OWNER, TABLE_NAME, INDEX_NAME, INDEX_TYPE    HAVING SUM(S.BYTES) > 1024 * 1024),  TMP2 AS   (SELECT INDEX_OWNER,           INDEX_NAME,           PLAN_OPERATION,           (SELECT MIN(TO_CHAR(NB.BEGIN_INTERVAL_TIME, 'YYYY-MM-DD HH24:MI:SS'))              FROM DBA_HIST_SNAPSHOT NB             WHERE NB.SNAP_ID = V.MIN_SNAP_ID) MIN_DATE,           (SELECT MAX(TO_CHAR(NB.END_INTERVAL_TIME, 'YYYY-MM-DD HH24:MI:SS'))              FROM DBA_HIST_SNAPSHOT NB             WHERE NB.SNAP_ID = V.MAX_SNAP_ID) MAX_DATE,           COUNTS      FROM (SELECT D.OBJECT_OWNER INDEX_OWNER,                    D.OBJECT_NAME INDEX_NAME,                    D.OPERATION || ' ' || D.OPTIONS PLAN_OPERATION,                    MIN(H.SNAP_ID) MIN_SNAP_ID,                    MAX(H.SNAP_ID) MAX_SNAP_ID,                    COUNT(1) COUNTS               FROM DBA_HIST_SQL_PLAN D, DBA_HIST_SQLSTAT H              WHERE D.OPERATION LIKE '%INDEX%'           AND D.SQL_ID = H.SQL_ID              GROUP BY D.OBJECT_OWNER, D.OBJECT_NAME, D.OPERATION, D.OPTIONS) V)  SELECT A.TABLE_OWNER,         A.TABLE_NAME,         A.INDEX_OWNER,         A.INDEX_NAME,         A.CREATED,         A.INDEX_TYPE,         A.INDEX_MB,               A.COUNT_INDEX_COLS,         B.PLAN_OPERATION,         CASE           WHEN MIN_DATE IS NULL THEN            (SELECT MIN(TO_CHAR(NB.BEGIN_INTERVAL_TIME, 'YYYY-MM-DD HH24:MI:SS'))               FROM DBA_HIST_SNAPSHOT NB)           ELSE            MIN_DATE         END AS  MIN_DATE,         CASE           WHEN MAX_DATE IS NULL THEN            (SELECT MAX(TO_CHAR(NB.BEGIN_INTERVAL_TIME, 'YYYY-MM-DD HH24:MI:SS'))               FROM DBA_HIST_SNAPSHOT NB)           ELSE            MAX_DATE         END AS  MAX_DATE,         COUNTS    FROM TMP1 A    LEFT OUTER JOIN TMP2 B      ON (A.INDEX_OWNER = B.INDEX_OWNER AND A.INDEX_NAME = B.INDEX_NAME);  

假设有如下的运行结果:

从图中可以看到有一个3.6G大的索引在13号到22号从没使用过,接下来,可以继续查询该索引是否是联合索引,创建是否合理,分析为何不走该索引,从而判断是否可以删除索引。

& 说明:

有关索引的监控过程可以参考我的BLOG:http://blog.itpub.net/26736162/viewspace-2120752/

本文选自《Oracle程序员面试笔试宝典》,作者:李华荣。