暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

【SQL杂货铺】索引管理

原创 闫伟 2023-01-30
1159

一、索引管理

1、获取索引定义

select dbms_metadata.get_ddl('INDEX','INDEX_NAME','INDEX_OWNER') from dual;

 

2、查询表的索引

select * from user_indexes where table_name='表名';

select * from user_ind_columns  where index_name='索引名';

3、查询索引占用大小

select owner,segment_name,(sum(bytes)/1024/1024)||'MB',tablespace_name from dba_segments where segment_name = 'IDX_T'  group by owner,segment_name,tablespace_name;

 

4、列出失效索引或索引分区

--以下三个脚本分别列出数据库中的失效的索引、索引分区、子分区:

REM list of the unusable index,index partition,index subpartition in Database

 

Select owner, index_name, status

  From dba_indexes

 where status = 'UNUSABLE'

   and owner not in ('SYS','SYSTEM',

                     'SYSMAN',

                     'EXFSYS',

                     'WMSYS',

                     'OLAPSYS',

                     'OUTLN',

                     'DBSNMP',

                     'ORDSYS',

                     'ORDPLUGINS',

                     'MDSYS',

                     'CTXSYS',

                     'AURORA$ORB$UNAUTHENTICATED',

                     'XDB',

                     'FLOWS_030000',

                     'FLOWS_FILES')

 order by 1, 2

/

 

select index_owner, index_name, partition_name

  from dba_ind_partitions

 where status ='UNUSABLE'

   and index_owner not in ('SYS',

                           'SYSTEM',

                           'SYSMAN',

                           'EXFSYS',

                           'WMSYS',

                           'OLAPSYS',

                           'OUTLN',

                           'DBSNMP',

                           'ORDSYS',

                           'ORDPLUGINS',

                           'MDSYS',

                           'CTXSYS',

                           'AURORA$ORB$UNAUTHENTICATED',

                           'XDB',

                           'FLOWS_030000',

                           'FLOWS_FILES') order by 1,2

/

 

Select  Index_Owner

     , Index_Name

     , partition_name

     , SUBPARTITION_NAME

 From

       DBA_IND_SUBPARTITIONS

Where

       status = 'UNUSABLE'  

       and index_owner not in ('SYS',

                           'SYSTEM',

                           'SYSMAN',

                           'EXFSYS',

                           'WMSYS',

                           'OLAPSYS',

                           'OUTLN',

                           'DBSNMP',

                           'ORDSYS',

                           'ORDPLUGINS',

                           'MDSYS',

                           'CTXSYS',

                           'AURORA$ORB$UNAUTHENTICATED',

                           'XDB',

                           'FLOWS_030000',

                           'FLOWS_FILES') order by 1, 2

/

5、查询索引碎片的比例

注意x$kdxst是oracle的一个内存表,然后analyze index indexname validate structure这条语句会往x$kdxst写一些统计信息,当执行select * from x$kdxst的时候,oracle这里实际上是把你执行analyze index indexname validate structure时的那个indexname给当作绑定变量给传进来了,所以你只能看到你执行analyze index indexname validate structure的那个index的统计信息。也就是只有在执行过analyze index indexname validate structure后且在同一个session下才能从index_stats中看到数据

analyze index indexname validate structure;

select name,del_lf_rows,lf_rows, round(del_lf_rows/decode(lf_rows,0,1,lf_rows)*100,0)||'%' frag_pct from index_stats where round(del_lf_rows/decode(lf_rows,0,1,lf_rows)*100,0)>30;

6、监控oracle数据库索引使用情况

监控索引一般有两种方式:

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

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

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

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

2)schema级别索引监控

如果想在系统中监控所有的索引,可以通过下面脚本实现监控数据库所有的索引。注意我们要排除一些系统表的索引、以及LOB indexes。可以直接执行脚本来开启索引监控,当然监控索引时长非常重要,太短的话有可能导致查询出来的数据有问题,一般建议监控一周后即可,OLAP系统则需要适当延长监控的时间。

--1、开启索引监控

SELECT 'ALTER INDEX ' || owner || '.' || index_name || ' MONITORING USAGE;' enable_monitor,

       'ALTER INDEX ' || owner || '.' || index_name ||

       ' NOMONITORING USAGE;' disable_monitor

  FROM dba_indexes

 WHERE INDEX_TYPE != 'LOB'

   and owner IN

       (SELECT username FROM dba_users WHERE account_status = 'OPEN')

   AND owner NOT IN ('SYS', 'SYSTEM', 'PERFSTAT', 'MGMT_VIEW', 'MONITOR',

        'SYSMAN', 'DBSNMP')

   AND owner not like '%SYS%';

--2、查询数据库中所有被监控索引的使用情况

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#;

--3、历史执行计划分析索引使用情况

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);

7、查看单个索引使用情况

--查看当前索引使用情况

SELECT p.object_name, p.operation, p.options, COUNT(1)

  FROM v$sql_plan p, v$sql s

 WHERE p.object_owner <> 'SYS'

   AND p.OBJECT_NAME in

       (select index_name

          from dba_indexes

         where table_name = 'S_SHIP_UNIT_LINE')

   AND p.sql_id = s.sql_id

 GROUP BY p.object_name, p.operation, p.options

 ORDER BY 1, 2, 3;

 

--查看历史索引使用情况

SELECT p.object_name, p.operation, p.options, COUNT(1)

  FROM dba_hist_sql_plan p, dba_hist_sqlstat s

 WHERE p.object_owner <> 'SYS'

   AND p.object_name in

       (select index_name

          from dba_indexes

         where table_name = 'S_SHIP_UNIT_LINE')

   AND p.sql_id = s.sql_id

 GROUP BY p.object_name, p.operation, p.options

 ORDER BY 1, 2, 3;

8、获得索引使用频率脚本(idx_usage_detail.sql)

下面的脚本将得到索引的使用率,可以很好的度量索引的使用情况以及根据这个值来判断当前的这些索引是否可以被移除或改进。

--1、数据库索引的使用频率脚本(idx_usage_detail.sql)

set linesize 140

set pagesize 160

 

clear breaks

clear computes

 

break on TABLE_NAME skip 2 ON INDEX_NAME ON INDEX_TYPE ON MB

compute sum of NR_EXEC on TABLE_NAME SKIP 2

compute sum of MB on TABLE_NAME SKIP 2

 

 

SET TIMI OFF

set linesize 140

set pagesize 10000

set verify off

col OWNER noprint

col TABLE_NAME for a30 heading 'Table name'

col INDEX_NAME for a30 heading 'Index name'

col INDEX_TYPE for a15 heading 'Index type'

col INDEX_OPERATION for a21 Heading 'Index operation'

col NR_EXEC for 9G999G990 heading 'Executions'

col MB for 999G990D90 Heading 'Index|Size MB' justify  right

 

        WITH Q AS (

                SELECT

                       S.OWNER                  A_OWNER,

                       TABLE_NAME               A_TABLE_NAME,

                       INDEX_NAME               A_INDEX_NAME,

                       INDEX_TYPE               A_INDEX_TYPE,

                       SUM(S.bytes) / 1048576   A_MB

                  FROM DBA_SEGMENTS S,

                       DBA_INDEXES  I

                 WHERE S.OWNER =  '&&1'

                   AND I.OWNER =  '&&1'

                   AND INDEX_NAME = SEGMENT_NAME

                 GROUP BY S.OWNER, TABLE_NAME, INDEX_NAME, INDEX_TYPE

                HAVING SUM(S.BYTES) > 1048576 * &&2

        )

        SELECT /*+ NO_QUERY_TRANSFORMATION(S) */

               A_OWNER                                    OWNER,

               A_TABLE_NAME                               TABLE_NAME,

               A_INDEX_NAME                               INDEX_NAME,

               A_INDEX_TYPE                               INDEX_TYPE,

               A_MB                                       MB,

               DECODE (OPTIONS, null, '       -',OPTIONS) INDEX_OPERATION,

               COUNT(OPERATION)                           NR_EXEC

         FROM  Q,

               DBA_HIST_SQL_PLAN d

         WHERE

               D.OBJECT_OWNER(+)= q.A_OWNER AND

               D.OBJECT_NAME(+) = q.A_INDEX_NAME

        GROUP BY

               A_OWNER,

               A_TABLE_NAME,

               A_INDEX_NAME,

               A_INDEX_TYPE,

               A_MB,

               DECODE (OPTIONS, null, '       -',OPTIONS)

        ORDER BY

               A_OWNER,

               A_TABLE_NAME,

               A_INDEX_NAME,

               A_INDEX_TYPE,

               A_MB DESC,

               NR_EXEC DESC

;

 

PROMPT "Showed only indexes in &&1 schema whose size > &&2 MB in period:"

 

SET HEAD OFF;

select to_char (min(BEGIN_INTERVAL_TIME), 'DD.MM.YYYY')

       || '-' ||

       to_char (max(END_INTERVAL_TIME), 'DD.MM.YYYY')

from dba_hist_snapshot;

 

SET HEAD ON

SET TIMI ON

 

 

 

--2、获得当前数据库索引的使用频率

--当前数据库中schema为RFUSER且索引大小大于100MB的索引的使用频率

SQL> @idx_usage_detail.sql

Enter value for 1: RFUSER

Enter value for 2: 100

 

9、索引质量分析脚本

对于生产环境中的数据库,可以通过查询相关数据字典得到索引的质量的高低,通过这个分析来指导如何改善索引的性能。

--1、script name: idx_quality.sql     

--Author : Leshami  

--index quality retrieval

SET LINESIZE 145

SET PAGESIZE 1000

SET VERIFY OFF

 

CLEAR COMPUTES

CLEAR BREAKS

 

BREAK ON table_name ON num_rows ON blocks

 

COLUMN owner FORMAT a14 HEADING 'Index owner'

COLUMN table_name FORMAT a25 HEADING 'Table'

COLUMN index_name FORMAT a25 HEADING 'Index'

COLUMN num_rows FORMAT 999G999G990 HEADING 'Table|Rows'

COLUMN MB FORMAT 9G990 HEADING 'Index|Size MB'

COLUMN blocks HEADING 'Table|Blocks'

COLUMN num_blocks FORMAT 9G990 HEADING 'Data|Blocks'

COLUMN avg_data_blocks_per_key FORMAT 999G990 HEADING 'Data Blks|per Key'

COLUMN avg_leaf_blocks_per_key FORMAT 999G990 HEADING 'Leaf Blks|per Key'

COLUMN clustering_factor FORMAT 999G999G990 HEADING 'Clust|Factor'

COLUMN Index_Quality FORMAT A13 HEADING 'Index|Quality'

 

--SPOOL index_quality

SELECT i.table_name,

         t.num_rows,

         t.blocks,

         i.index_name,

         o.bytes / 1048576 mb,

         i.avg_data_blocks_per_key,

         i.avg_leaf_blocks_per_key,

         i.clustering_factor,

         CASE

            WHEN NVL (i.clustering_factor, 0) = 0 THEN '0-No Stats'

            WHEN NVL (t.num_rows, 0) = 0 THEN '0-No Stats'

            WHEN (ROUND (i.clustering_factor / t.num_rows * 100)) < 6 THEN '5-Excellent'

            WHEN (ROUND (i.clustering_factor / t.num_rows * 100)) BETWEEN 7 AND 11 THEN '4-Very Good'

            WHEN (ROUND (i.clustering_factor / t.num_rows * 100)) BETWEEN 12 AND 15 THEN '2-Good'

            WHEN (ROUND (i.clustering_factor / t.num_rows * 100)) BETWEEN 16 AND 25 THEN '2-Fair'

            ELSE '1-Poor'

         END

            index_quality

    FROM dba_indexes i, dba_segments o, dba_tables t

   WHERE

     --    i.index_name LIKE UPPER ('%&&1%') AND

         i.owner = t.owner

         AND i.table_name = t.table_name

         AND i.owner = o.owner

         AND i.index_name = o.segment_name

         AND t.owner = UPPER('&input_owner')

         AND t.table_name LIKE UPPER('%&input_tbname%')

ORDER BY table_name,

         num_rows,

         blocks,

         index_quality DESC;

 

--SPOOL OFF;

==============================================================

 

--2、获取指定schema或表上的索引质量信息报告

SQL> @idx_quality.sql

Enter value for input_owner: RFUSER

Enter value for input_tbname: TAB_GOODSLABEL --省略具体的表名则会输出整个schema的索引质量报告

9、查询单表上索引列的相关信息   

对于上面索引质量比较低的索引还应结合该索引的使用频率来考量该索引存在的必要性,对于聚簇因子,只能通过重新组织表上的数据来,以及调整相应索引列的顺序得以改善。大多数情况下,单表上6-7个索引是比较理想的。过多的索引导致过大的资源开销,以及降低DML性能。

--1、script name: idx_info.sql

--get the index column information by specified table

set linesize 180

col cl_nam format a20

col table_name format a25

col cl_pos format 9

col idx_typ format a15

SELECT b.table_name,

           a.index_name,

           a.column_name     cl_nam,

           a.column_position cl_pos,

           b.status,

           b.index_type      idx_typ,

           a.descend         dscd

FROM   dba_ind_columns a, dba_indexes b

WHERE  a.index_name = b.index_name

           AND owner = upper('&owner')

           AND a.table_name LIKE upper('%&table_name%')

ORDER  BY 2, 4;

 

--2、查询单表上索引列的相关信息

SQL> @idx_info.sql

Enter value for owner: RFUSER

Enter value for table_name: TAB_GOODSLABEL

 

最后修改时间:2023-01-30 16:20:12
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论