index


索引由 Oracle 服务器自动使用和维护,一旦一个索引被创建,它就不再需要用户直接管理。rowid是一个十六进制的串,表示包含块定义的行地址,行的位置在块中,并且有数据库文件标识符,访问任何指定行的最快的方法是引用它的 rowid.

索引里存储的内容: ROWID 、索引列(键值)。

创建索引可以大大提高系统的性能,总体来说,索引的优点如下所示:

  1. 大大加快数据的检索速度,这也是创建索引的最主要的原因。
  2.  索引可以加速表和表之间的连接。
  3.  索引在实现数据的参照完整性方面特别有意义,例如在外键列上创建索引可以有效的避免死锁的发生,
  4.  也可以防止当更新父表主键时,数据库对子表的全表锁定。
  5.  索引是减少磁盘 I/O 的许多有效手段之一。
  6.  当使用分组(GROUP BY)和排序(ORDER BY)子句进行数据检索时,可以显著减少查询中分组和排序的时间,大大加快数据的检索速度。
  7.  创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
  8.  通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

索引的缺点如下所示:

  1.  索引必须创建在表上,不能创建在视图上。
  2.  创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
  3.  建立索引需要占用物理空间,如果要建立聚簇索引,那么需要的空间会很大。
  4.  当对表中的数据进行增加、删除和修改的时候,系统必须要有额外的时间来同时对索引进行更新维护,以维持数据和索引的一致性,所以,索引降低了数据的维护速度

索引的使用原则:

  1. 在大表上建立索引才有意义。
  2. 在 WHERE 子句或是连接条件经常引用的列上建立索引。
  3. 索引的层次不要超过 4 层。
  4. 如果某属性常作为最大值和最小值等聚集函数的参数,那么考虑为该属性建立索引。
  5. 表的主键、外键必须有索引
  6. 创建了主键和唯一约束后会自动创建唯一索引。
  7. 经常与其它表进行连接的表,在连接字段上应该建立索引。
  8. 经常出现在 WHERE 子句中的字段,特别是大表的字段,应该建立索引。
  9. 要索引的列经常被查询,并只返回表中的行的总数的一小部分。
  10. 对于那些查询中很少涉及的列、重复值比较多的列尽量不要建立索引。
  11. 经常出现在关键字 ORDER BY、GROUP BY、DISTINCT 后面的字段,最好建立索引。
  12. 索引应该建在选择性高的字段上。
  13. 索引应该建在小字段上,对于大的文本字段甚至超长字段,不适合建索引。对于定义为 CLOB、TEXT、IMAGE 和 BIT 的数据类型的列不适合建立索引。
  14. 复合索引的建立需要进行仔细分析。正确选择复合索引中的前导列字段,一般是选择性较好的字段。
  15. 如果单字段查询很少甚至没有,那么可以建立复合索引;否则考虑单字段索引。
  16. 如果复合索引中包含的字段经常单独出现在 WHERE 子句中,那么分解为多个单字段索引。
  17. 如果复合索引所包含的字段超过 3 个,那么仔细考虑其必要性,考虑减少复合的字段。
  18. 如果既有单字段索引,又有这几个字段上的复合索引,那么一般可以删除复合索引。
  19. 频繁进行 DML 操作的表,不要建立太多的索引。
  20. 删除无用的索引,避免对执行计划造成负面影响

一个表中定义一个列为主键,或者定义一个唯一键约束时 Oracle 服务器自动创建该索引,索引的名字习惯上是约束的名字

 另外,需要特别注意的是,索引不存储空值

为什么不走索引(339页详解)

位图索引

  1. 适合于决策支持系统(DSS)或 OLAP 系统。位图索引主要用于数据仓库,或在以特定方式引用很多列的查询环境中。位图索引并不适合许多 OLTP 应用程序,若使用不当则容易产生死锁。
  2. 被索引的表是只读的,或 DML 语句不会对其进行频繁修改的表。
  3. 非常适合 OR 操作符的查询。
  4. 位图索引不直接存储 ROWID,而是存储字节位到 ROWID 的映射
  5. 减少响应时间。
  6. 节省空间占用。
  7. 在同一列上建立位图索引后就不能再建立普通索引了,但是可以建立函数索引,位图索引可以和函数索引同时建立。
  8. 做 UPDATE 代价非常高。
  9. 基于规则的优化器不会考虑位图索引。
  10. 当执行 ALTER TABLE 语句并修改包含有位图索引的列时,会使位图索引失效。
  11. 位图索引不包含任何列数据,并且不能用于任何类型的完整性检查。
  12. 位图索引不能被声明为唯一索引。
  13. 位图索引的最大长度为 30。
  14. 位图索引适合创建在低基数列(即列值重复率很高)上。

函数索引

创建索引的函数里面不能使用 SUM、COUNT 等聚合函数
不能在 LOB 类型的列、NESTED TABLE 列上创建函数索引。
不能使用 SYSDATE、USER 等非确定性函数。
对于任何用户自定义函数必须显式的声明 DETERMINISTIC 关键字,否则会报错:“ora-30553: thefunction is not deterministic”
使用函数索引有几个先决条件:
(1)必须拥有 CREATE INDEX 和 QUERY REWRITE(本模式下)或 CREATE ANY INDEX 和 GLOBAL QUERY REWRITE(其它模式下)权限。
(2)必须使用基于成本的优化器,基于规则的优化器将被忽略。
(3)参数 QUERY_REWRITE_INTEGRITY 和 QUERY_REWRITE_ENABLED 可以保持默认值

索引组织表(IOT)

索引中存储的是行的实际数据,而不是 ROWID,它是基于主键访问数据的。在索引组织表中,索引就是数据,数据就是索引

辅助索引(Secondary Indexes)也叫二级索引,是一个建立在索引组织表上的索引。在某种意义上,它是一个索引的索引。辅助索引是一个独立的模式对象,并与索引组织表分开存储。索引表上的辅助索引能够非常有效地访问索引表,这种索引既不是使用主键列也不是使用主键的某个前缀。Oracle 构造这种索引使用的是逻辑的行标识符(Logical Rowids),这种 ROWIDS 是基于表的主键(而不是基于行的物理地址)。这种逻辑 ROWIDS 包括了一个物理猜想(Physical Guess),它也是一种物理标识符(物理指针),它唯一标识行的块地址,Oracle 能使用这些猜想直接对索引表的叶块进行探测,从而避免主键搜索。

当创建 IOT 时,必须要设定主键,否则报错。

 分区索引

如果使用了位图索引,那么就必须是本地索引
本地分区索引可分为以下类别:

  • 本地前缀索引(Local Prefixed Indexes)在这种情况下,分区键处于索引定义的前导部分。
  • 本地非前缀索引(Local Nonprefixed Indexes)在这种情况下,分区键不是索引列列表的前导部分,甚至根本不必在该列表中。
CREATE INDEX IDX_PART_RANGE_ID ON T_PARTITION_RANGE(ID) LOCAL (
PARTITION I_RANGE_P1 TABLESPACE TS_DATA01,
PARTITION I_RANGE_P2 TABLESPACE TS_DATA02,
PARTITION I_RANGE_P3 TABLESPACE TS_DATA03,
PARTITION I_RANGE_PMAX TABLESPACE TS_DATA04
);

全局分区索引是一个 B-Tree 索引,全局索引(Global Index)既可以分区(全局分区索引),也可以不分区(普通索引),既可以建 RANGE分区,也可以建 HASH 分区,既可创建于分区表上,也可以创建于非分区表上,就是说,全局索引是完全独立的,因此,它也需要更多的维护操作

  • 全局索引可以依附于分区表,也可以依附于非分区表。
  • 全局分区索引的索引条目可能指向若干个分区,因此,对于全局分区索引,即使只截断一个分区中的数据,也需要 REBULID 若干个分区甚至是整个索引。
  • 全局索引多应用于 OLTP 系统中。
  • 全局分区索引只按 RANGE 或者 HASH 分区,HASH 分区是 Oracle 10g 以后才支持的。
  • 在 Oracle 9i 以后对分区表做 MOVE 或者 TRUNCATE 的时候可以用 UPDATE GLOBAL INDEXES 语句来同步更新全局分区索引,用消耗一定资源来换取高度的可用性。
  • 若在表中使用 A 列作分区,但在索引中用 B 列作本地索引,若 WHERE 条件中用 B 来查询,那么 Oracle会扫描所有的表和索引的分区,成本会比分区更高,此时可以考虑用 B 列做全局分区索引和用 A 列做本地索引。
  • 在创建索引时,如果不显式指定 GLOBAL 或 LOCAL,那么默认是 GLOBAL。
  • 在创建 GLOBAL 索引时,如果不显式指定分区子句,那么默认不分区。
  • 含有子分区的分区索引有大小,但是在数据字典视图中的列 SEGMENT_CREATED 的值显示为 N/A,STATUS 的值也显示为 N/A。

Truncate 分区操作会导致全局索引失效; truncate 普通表对索引没有影响;

Truncate 分区操作不会释放全局索引中的空间,而truncate 普通表会释放索引所占空间;

rename 表名操作对索引没有影响,因为rename操作只是更改了数据字典,表中数据行的rowid并没有发生变化

全文索引

Oracle 全文索引使 Oracle 具备了强大的文本检索能力和智能化的文本管理能力。Oracle 将全文检索功能做为内置功能提供给用户,使得用户在创建数据库实例时自动安装全文检索。要使用 Oracle 全文索引,必须具有 CTXAPP 角色或者是 CTXSYS 用户。Oracle 全文索引为系统管理员提供 CTXSYS 用户,为应用程序开发人员提供 CTXAPP 角色。具有 CTXAPP 角色的用户可以使用全文索引

 虚拟索引

不可见索引

ALTER INDEX INDEX_NAME INVISIBLE; --修改索引不可见
ALTER INDEX INDEX_NAME VISIBLE; --修改索引可见

不可见索引的特点主要有以下几点:
(1)当索引变更为不可见的时候,只是对 Oracle 的优化器不可见。
(2)不可见索引在 DML 操作的时候也会被维护。
(3)加 HNIT 对不可见索引无效。
(4)可以通过修改 SYSTEM 级别和 SESSION 级别参数来使用不可见索引。

反向键索引(Reverse Key Indexes) 

只有对反向键索引列进行“=”操作时,其反向键索引才会使用。(在 WHERE 子句中使用“BETWEEN AND”语句或比较运算符“>”、“<”、“>=”、“<=”等),那么反向键索引将不会被使用

反向键索引应用场合:
1、在索引叶块成为热点块时使用
2、在 RAC 环境中使用
3、反向键索引通常建立在值是连续增长的列上,使数据均匀地分布在整个索引上。

创建索引
create index emp_last_name_idx on employees(last_name) online parallel 2;            ---普通单列索引
CREATE INDEX IDX_CI_emp ON employees(OBJECT_ID,OBJECT_TYPE);     ---复合索引(一般情况下,把最常被访问和选择性较高的列放在前面)
CREATE INDEX upper_last_name_idx ON employees(UPPER(last_name));          ---函数索引
CREATE BITMAP INDEX IDX_SEX_LHR ON T_USER(SEX);              ---创建位图索引
CREATE TABLE IND_ORG_TAB_LHR(VENCODE NUMBER(4) PRIMARY KEY,VENNAME VARCHAR2(20)) ORGANIZATION INDEX;        ---索引组织表
CREATE INDEX DOC_INDEX_LHR ON XT_DOCS_LHR(TEXT) INDEXTYPE IS CTXSYS.CONTEXT;           ---创建全文索引
CREATE INDEX REV_INDEX_LHR ON XT_REVI_LHR(OBJECT_ID) REVERSE;                  ---创建反向键索引

DROP INDEX IDX_NAME_LHR FORCE;                ---删除索引

查看索引信息

SELECT IC.INDEX_NAME,IC.COLUMN_NAME,IC.COLUMN_POSITION COL_POS,IX.UNIQUENESS FROM USER_INDEXES IX, USER_IND_COLUMNS IC WHERE IC.INDEX_NAME = IX.INDEX_NAME
AND IC.TABLE_NAME = 'EMPLOYEES';                      ---查询某个表上的索引

SELECT D.INDEX_NAME,D.TABLE_NAME,D.COLUMN_NAME FROM DBA_IND_COLUMNS D WHERE D.INDEX_NAME='IDX_CI_20170628_LHR';  ---查询复合索引列

SELECT * FROM DBA_INDEXES D WHERE D.INDEX_TYPE LIKE 'FUNCTION-BASED%';  ---查询所有的函数索引

SELECT * FROM DBA_INDEXES D WHERE D.INDEX_TYPE='BITMAP';           ---查询所有的位图索引
SELECT * FROM DBA_INDEXES D WHERE D.JOIN_INDEX='YES';              ---查询所有的位图连接索引

SELECT * FROM DBA_TABLES D WHERE D.IOT_TYPE='IOT';               ---查询所有的IOT表

SELECT * FROM DBA_INDEXES D WHERE D.INDEX_TYPE LIKE '%/REV'; ---查询反向键索引

 获取索引定义

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

索引选择性

 

SELECT INDEX_NAME,DISTINCT_KEYS/NUM_ROWS SELECTIVITY FROM DBA_INDEXES;
毋庸置疑,主键的选择性为 1。选择性越接近 1,那么该索引就越好。

 

查询索引大小

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;

---查询大索引
col owner for a10
col segment_name for a32
select * from (select owner,segment_name,bytes/1024/1024 SIZE_MB from dba_segments where owner in ('TEST') and segment_type like '%INDEX%' order by 3 desc) where rownum < 11;

Oracle 11gR2 中使用 EXPLAIN PLAN FOR CREATE INDEX 时,Oracle会提示评估的索引大小(ESTIMATED INDEX SIZE)

EXPLAIN PLAN FOR CREATE INDEX IDX_T ON SYS.TEST_INDEX_SIZE(OBJECT_ID);
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY());

查询索引碎片比例

analyze index ID_IND 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;
注意:x$kdxstoracle的一个内存表,然后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中看到数据

索引失效情况:

当某些操作导致数据行的 ROWID 改变,索引就会完全失效。可以分普通表和分区表来讨论哪些操作将导致索引失效。

(1)普通表索引失效的情形如下所示:

1、手动置索引无效:ALTER INDEX IND_OBJECT_ID UNUSABLE;。

2、如果对表进行 MOVE 操作(包含移动表空间和压缩操作)或在线重定义表后,那么该表上所有的索引状态会变为 UNUSABLE。MOVE 操作的 SQL 语句为:ALTER TABLE TT MOVE;。

3、SQL*Loader加载数据。在SQL*Loader加载过程中会维护索引,由于数据量比较大,在SQL*Loader加载过程中出现异常情况,也会导致Oracle来不及维护索引,导致索引处于失效状态,影响查询和加载。异常情况主要有:在加载过程中杀掉 SQL*Loader 进程、重启或表空间不足等。

(2)分区表索引失效的情形如下所示:

1、对分区表的某个含有数据的分区执行了 TRUNCATE、DROP 操作可以导致该分区表的全局索引失效,而分区索引依然有效,如果操作的分区没有数据,那么不会影响索引的状态。需要注意的是,对分区表的 ADD 

操作对分区索引和全局索引没有影响。

2 执行 EXCHANGE 操作后,全局索引和分区索引都无条件地会被置为 UNUSABLE(无论分区是否含有数据)。但是,若包含 INCLUDING INDEXES 子句(缺省情况下为 EXCLUDING 

INDEXES),则全局索引会失效,而分区索引依然有效。

3 如果执行 SPLIT 的目标分区含有数据,那么在执行 SPLIT 操作后,全局索引和分区索引都会被被置为UNUSABLE。如果执行 SPLIT 的目标分区没有数据,那么不会影响索引的状态。

4 对分区表执行 MOVE 操作后,全局索引和分区索引都会被置于无效状态。

5 手动置其无效:ALTER INDEX IND_OBJECT_ID UNUSABLE;。对于分区表而言,除了 ADD 操作之外,TRUNCATE、DROP、EXCHANGE 和 SPLIT 操作均会导致全局索引失

效,但是可以加上 UPDATE GLOBAL INDEXES 子句让全局索引不失效。重建分区索引的命令为:ALTER INDEX IDX_RANG_LHR REBUILD PARTITION P1;。

列出失效索引或索引分区

select owner, index_name, status From dba_indexes where status='UNUSABLE' and owner in ('FENG') order by 1,2;
select index_owner,index_name,partition_name,subpartition_name from dba_ind_subpartitions where status='unusable' and index_owner in('FENG');

重建索引

 

alter index indexname rebuild online tablespace t1;
alter index indexname rebuild partition paritionname tablespace tablespacename; alter index indexname rebuild subpartition partitioname tablespace tablespacename;
alter index index_name coalesce
1、rebuild以index fast full scan(or table full scan) 方式读取原索引中的数据来构建一个新的索引,有排序的操作; rebuild online 执行表扫描获取数据,有排序的操作; 2、rebuild 会阻塞 dml 操作 ,rebuild online 不会阻塞 dml 操作; 3、rebuild online 时系统会产生一个 SYS_JOURNAL_xxx 的 IOT 类型的系统临时日志表,所有 rebuild online 时索引的变化都记录在这个表中,当新的索引创建完成后,把这个表的记录维护到新的索引中去,然后 drop 掉旧的索引 4、Rebuild操作会产生大量redo log;
5、使用带有coalesce参数时重建期间不需要额外空间,它只是在重建索引时将处于同一个索引分支内的叶块拼合起来,这最大限度的减少了与查询过程中相关的潜在的加锁问题,但是,coalesce选项不能用来将一个索引转移到其他表空间。

 

 

监控索引使用情况

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

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

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

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

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

2schema级别索引监控

如果想在系统中监控所有的索引,可以通过下面脚本实现监控数据库所有的索引。注意我们要排除一些系统表的索引、以及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);

 查看某个表索引使用情况

某个用户的某个表的索引信息
--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;

--
查看某个表索引使用情况 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;

 

 

 

附录:

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、索引质量分析脚本

--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的索引质量报告

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM