Oracle之不可见索引

1  BLOG文档结构图

2  前言部分

2.1  导读和注意事项

各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~:

① Oracle不可见索引的使用

  Tips:

① 本文在ITpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和微信公众号(xiaomaimiaolhr)有同步更新

② 文章中用到的所有代码,相关软件,相关资料请前往小麦苗的云盘下载(http://blog.itpub.net/26736162/viewspace-1624453/)

③ 若文章代码格式有错乱,推荐使用搜狗、360或QQ浏览器,也可以下载pdf格式的文档来查看,pdf文档下载地址:http://blog.itpub.net/26736162/viewspace-1624453/,另外itpub格式显示有问题,可以去博客园地址阅读

④ 本篇BLOG中命令的输出部分需要特别关注的地方我都用灰色背景和粉红色字体来表示,比如下边的例子中,thread 1的最大归档日志号为33,thread 2的最大归档日志号为43是需要特别关注的地方;而命令一般使用黄色背景和红色字体标注;对代码或代码输出部分的注释一般采用蓝色字体表示。

List of Archived Logs in backup set 11

Thrd Seq     Low SCN    Low Time            Next SCN   Next Time

---- ------- ---------- ------------------- ---------- ---------

1    32      1621589    2015-05-29 11:09:52 1625242    2015-05-29 11:15:48

1    33      1625242    2015-05-29 11:15:48 1625293    2015-05-29 11:15:58

2    42      1613951    2015-05-29 10:41:18 1625245    2015-05-29 11:15:49

2    43      1625245    2015-05-29 11:15:49 1625253    2015-05-29 11:15:53

[ZHLHRDB1:root]:/>lsvg -o

T_XDESK_APP1_vg

rootvg

[ZHLHRDB1:root]:/>

00:27:22 SQL> alter tablespace idxtbs read write;

====》2097152*512/1024/1024/1024=1G

本文如有错误或不完善的地方请大家多多指正,ITPUB留言或QQ皆可,您的批评指正是我写作的最大动力。

2.2  相关参考文章连接

Oracle之虚拟索引:http://blog.itpub.net/26736162/viewspace-2123687/

Oracle索引的监控:http://blog.itpub.net/26736162/viewspace-2120752/

oracle 如何预估将要创建的索引的大小:http://blog.itpub.net/26736162/viewspace-1381160/

3  不可见索引(Invisible Indexes)

您常常感到疑惑,索引是否真的有利于用户的查询?它可能有利于一个查询,但会影响 10 个其他查询。索引肯定会对 INSERT 语句造成负面影响,也会执行潜在的删除和更新操作,这取决于WHERE 条件是否在索引中包括该列。一个相关的问题是,使用索引时,如果该索引被删除,会对查询性能造成什么影响?当然,您可以删除索引并查看对查询的影响,但说起来容易做起来难。索引实际上如何有助于查询?您必须重新定义索引,为此,需要进行重新创建。完全重新创建之后,就没有人能使用它了。重新创建索引也是一个昂贵的过程;它会占用许多有用的数据库资源。

我们经常在数据库上建索引或删除索引,由于索引对SQL的执行性能影响非常大,有可能变得很好,也有可能变得很差,在线下开发环境我们可以充分测试,对于创建或删除索引没什么问题。但是在线上环境,由于高并发的访问,如果我们删除了一个重要的大索引(GB以上),删除后才发现大量SQL性能变差,很快主机就LOAD飙升,系统无法运行了,由于索引已经删除,并且很大,要当场重建基本不可能,因为这个索引巨大,创建估计要几分钟甚至几个小时,况且这时主机已经基本没有响应,IO全部用光,只能把应用停了,等索引建好后再开始打开应用,等发生这样的事才会为自己的失误而后悔。那我们有没有办法让删除索引的风险降低呢,答案是有!即本文介绍的不可见索引。

索引维护是DBA的一项重要工作。当一个系统运行很长一段时间,经过需求变更、结构设计变化后,系统中就可能会存在一些不会被使用的索引,或者使用效率很低的索引。这些索引的存在,不仅占用系统空间,而且会降低事务效率,增加系统的waits。因此,我们需要找出那些无用或低效索引的索引并删除它们(找出无用索引可以通过索引监控的方法)。但是,直接删除索引还是存在一定风险的。例如,某些索引可能只是在一些周期的作业中被使用到,而如果监控周期没有覆盖到这些作业的触发点,就会认为索引是无用的而被删除。当作业启动后,可能就会对系统性能造成冲击。这时,可能就会手忙脚乱的去找回索引定义语句、重建索引。11G之前,我们可以先不删除索引,而将其修改为unusable。这样的话,索引的定义并未删除,只是索引不能再被使用也不会随着表数据的更新而更新。当需要重新使用该索引时,需要用rebuild语句重建、然后更新统计信息。对于一些大表来说,这个时间可能就非常长。在11g里,Oracle 提供了一个新的特性来降低直接删除索引或者禁用索引的风险,那就是索引不可见(Index Invisible)。

从版本11g 开始,可以创建不可见的索引。优化程序会忽略不可见的索引,除非在会话或系统级别上将 OPTIMIZER_USE_INVISIBLE_INDEXES初始化参数显式设置为TRUE。此参数的默认值是FALSE。

使索引不可见是使索引不可用或删除索引的一种替代办法。使用不可见的索引,可完成以下操作:

(1) 在删除索引之前测试对索引的删除。

(2) 对应用程序的特定操作或模块使用临时索引结构,这样就不会影响整个应用程序。

注意:与不可用的索引不同,不可见的索引在使用DML 语句期间仍会得到维护。

当索引不可见时,优化程序生成的计划不会使用该索引。如果未发现性能下降,则可以删除该索引。还可以创建最初不可见的索引,执行测试,然后确定是否使该索引可见。

可以查询*_INDEXES 数据字典视图的VISIBILITY 列来确定该索引是VISIBLE 还是INVISIBLE。

SQL> SELECT VISIBILITY FROM DBA_INDEXES WHERE INDEX_NAME='IDX_ID';

VISIBILIT

---------

VISIBLE

--创建不可见索引:

CREATE INDEX INDEX_NAME ON TABLE_NAME(COLUMN_NAME) INVISIBLE;

--修改索引是否可见:

ALTER INDEX INDEX_NAME INVISIBLE;

ALTER INDEX INDEX_NAME VISIBLE;

特点总结:

1、当索引变更为不可见的时候,只是对oracle的优化器不可见。

2、不可见索引在DML操作的时候也会被维护。

3、加HNIT对不可见索引无效。

4、可以通过修改system级别和session级别参数来使用不可见索引。

3.1  我的示例

创建表,不可见索引,并收集统计信息:

SYS@lhrdb> CREATE TABLE T_II_20160819_01_LHR AS SELECT * FROM DBA_OBJECTS;

Table created.

SYS@lhrdb> CREATE INDEX IDX_II_20160819 ON T_II_20160819_01_LHR(OBJECT_ID) INVISIBLE;

Index created.

SYS@lhrdb> SELECT VISIBILITY FROM DBA_INDEXES WHERE INDEX_NAME='IDX_II_20160819';

VISIBILIT

---------

INVISIBLE

SYS@lhrdb> EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME =>USER,TABNAME=>'T_II_20160819_01_LHR',DEGREE=>2,CASCADE => TRUE);

PL/SQL procedure successfully completed.

--带where条件查询:

SYS@lhrdb> SHOW PARAMETER OPTIMIZER_USE_INVISIBLE_INDEXES

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

optimizer_use_invisible_indexes      boolean     FALSE

SYS@lhrdb> set line 9999

SYS@lhrdb> set autot traceonly exp

SYS@lhrdb> SELECT * FROM T_II_20160819_01_LHR WHERE OBJECT_ID=1;

Execution Plan

----------------------------------------------------------

Plan hash value: 700947541

------------------------------------------------------------------------------------------

| Id  | Operation         | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |                      |     1 |    98 |   343   (2)| 00:00:05 |

|*  1 |  TABLE ACCESS FULL| T_II_20160819_01_LHR |     1 |    98 |   343   (2)| 00:00:05 |

------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("OBJECT_ID"=1)

--这里使用了全表扫描,根据唯一性,这里应该走索引的,我们加上hint试试

SYS@lhrdb> SELECT /*+index(T,IDX_II_20160819)*/ * FROM T_II_20160819_01_LHR T WHERE OBJECT_ID=1;

Execution Plan

----------------------------------------------------------

Plan hash value: 700947541

------------------------------------------------------------------------------------------

| Id  | Operation         | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |                      |     1 |    98 |   343   (2)| 00:00:05 |

|*  1 |  TABLE ACCESS FULL| T_II_20160819_01_LHR |     1 |    98 |   343   (2)| 00:00:05 |

------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("OBJECT_ID"=1)

--对于invisible的index,使用hint也没有用。

--修改OPTIMIZER_USE_INVISIBLE_INDEXES参数为TRUE,再次查询:

SYS@lhrdb> ALTER SESSION SET OPTIMIZER_USE_INVISIBLE_INDEXES=TRUE;

Session altered.

SYS@lhrdb> SELECT * FROM T_II_20160819_01_LHR WHERE OBJECT_ID=1;

Execution Plan

----------------------------------------------------------

Plan hash value: 2544197461

----------------------------------------------------------------------------------------------------

| Id  | Operation                   | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                      |     1 |    98 |     2   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T_II_20160819_01_LHR |     1 |    98 |     2   (0)| 00:00:01 |

|*  2 |  INDEX RANGE SCAN          | IDX_II_20160819      |     1 |       |     1   (0)| 00:00:01 |

----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("OBJECT_ID"=1)

--这次使用了索引。关闭 OPTIMIZER_USE_INVISIBLE_INDEXES参数,将索引改成visible,再测试:

SYS@lhrdb> ALTER SESSION SET OPTIMIZER_USE_INVISIBLE_INDEXES=FALSE;

Session altered.

SYS@lhrdb> ALTER INDEX IDX_II_20160819 VISIBLE;

Index altered.

SYS@lhrdb> SELECT * FROM T_II_20160819_01_LHR WHERE OBJECT_ID=1;

Execution Plan

----------------------------------------------------------

Plan hash value: 2544197461

----------------------------------------------------------------------------------------------------

| Id  | Operation                   | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |                      |     1 |    98 |     2   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T_II_20160819_01_LHR |     1 |    98 |     2   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | IDX_II_20160819      |     1 |       |     1   (0)| 00:00:01 |

----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - access("OBJECT_ID"=1)

--这次又正常了。

以上是Oracle11g的处理方法,但是在Oracle9i或Oracle10g中索引没有invisible的功能,我们如何处理呢?现在Oracle数据库一般都采用基于成本的计算方法来生成执行计划,只要索引的成本更低,ORACLE就会选择使用索引,OK,那我们只要告诉ORACLE使用这个索引成本很高,它就不会使用这个索引,这样就达到了暂时让索引不可用的效果。相信很多人都知道ORACLE提供了dbms_stats包来管理对像的统计信息,通过DBMS_STATS.SET_INDEX_STATS函数我们可以强制设置统计信息,现在我们只要把索引的成本设置成非常大即可,如下所示。

--设置非常离谱的统计信息,让ORACLE认为使用索引的成本很高

SYS@lhrdb> SELECT A.OWNER,A.INDEX_NAME,A.BLEVEL,A.LEAF_BLOCKS,A.NUM_ROWS FROM DBA_INDEXES A WHERE INDEX_NAME='IDX_II_20160819';

OWNER                          INDEX_NAME                         BLEVEL LEAF_BLOCKS   NUM_ROWS

------------------------------ ------------------------------ ---------- ----------- ----------

SYS                            IDX_II_20160819                         1         193      87133

SYS@lhrdb> EXEC DBMS_STATS.SET_INDEX_STATS(OWNNAME => user,INDNAME => 'IDX_II_20160819',INDLEVEL => 10,NUMLBLKS => 1000000000,NUMROWS => 100000000000,NO_INVALIDATE => FALSE );

PL/SQL procedure successfully completed.

SYS@lhrdb> col NUM_ROWS format 999999999999999

SYS@lhrdb> SELECT A.OWNER,A.INDEX_NAME,A.BLEVEL,A.LEAF_BLOCKS,A.NUM_ROWS FROM DBA_INDEXES A WHERE INDEX_NAME='IDX_II_20160819';

OWNER                          INDEX_NAME                         BLEVEL LEAF_BLOCKS         NUM_ROWS

------------------------------ ------------------------------ ---------- ----------- ----------------

SYS                            IDX_II_20160819                        10  1000000000     100000000000

no_invalidate=false表示让CACHE中的执行计划立即失效,重新按现在的统计信息生成SQL执行计划。验证一下是否生效:

SYS@lhrdb> set autot on9

SYS@lhrdb> SELECT * FROM T_II_20160819_01_LHR WHERE OBJECT_ID=1;

no rows selected

Execution Plan

----------------------------------------------------------

Plan hash value: 700947541

------------------------------------------------------------------------------------------

| Id  | Operation         | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |                      |     1 |    98 |   343   (2)| 00:00:05 |

|*  1 |  TABLE ACCESS FULL| T_II_20160819_01_LHR |     1 |    98 |   343   (2)| 00:00:05 |

------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("OBJECT_ID"=1)

Statistics

----------------------------------------------------------

0  recursive calls

0  db block gets

2491  consistent gets

0  physical reads

0  redo size

1343  bytes sent via SQL*Net to client

509  bytes received via SQL*Net from client

1  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

0  rows processed

3.2  OCP

An index called ORD_CUSTNAME_IX has been created on the CUSTNAME column in the ORDERS table using the following command:

SQL>CREATE INDEX ord_custname_ix ON orders(custname);

The ORDERS table is frequently queried using the CUSTNAME column in the WHERE clause.You want to check the impact on the performance of the queries if the index is not available.You do not want the index to be dropped or rebuilt to perform this test.

Which is the most efficient method of performing this task?

A.disabling the index

B.making the index invisible

C.making the index unusable

D.using the MONITORING USAGE clause for the index

Answer:B

答案解析:题目要求在不能删除和重建的情况下来测试索引的性能。

对于选项A,索引不能被禁用。所以,选项A错误。

对于选项B,让索引不可用,为正确选项。所以,选项B正确。

对于选项C,让索引不可用之后还是得重建索引。所以,选项C错误。

对于选项D,监控索引并不能测试索引在不可用的情况下对系统的性能影响。所以,选项D错误。

所以,本题的答案为B。

  About Me

..........................................................................................................................................................................................................

● 本文作者:小麦苗,只专注于数据库的技术,更注重技术的运用

● 本文在ITpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和个人微信公众号(xiaomaimiaolhr)上有同步更新

● QQ群:230161599 微信群:私聊

● 本文itpub地址:http://blog.itpub.net/26736162/viewspace-2124044/ 本文博客园地址:http://www.cnblogs.com/lhrbest/articles/5808049.html

● 本文pdf版:http://yunpan.cn/cdEQedhCs2kFz (提取码:ed9b)

● 小麦苗分享的其它资料:http://blog.itpub.net/26736162/viewspace-1624453/

● 联系我请加QQ好友(642808185),注明添加缘由

● 于 2016-08-19 09:00~ 2016-08-19 19:00 在中行完成

● 【版权所有,文章允许转载,但须以链接方式注明源地址,否则追究法律责任】

..........................................................................................................................................................................................................

长按识别二维码或微信客户端扫描下边的二维码来关注小麦苗的微信公众号:xiaomaimiaolhr,学习最实用的数据库技术。

转载于:https://www.cnblogs.com/lhrbest/articles/5808049.html

Oracle之不可见索引相关推荐

  1. Oracle表分区和索引分区汇总

    Oracle表分区和索引分区汇总 为了简化数据库大表的管理,例如在数据仓库中一般都是TB级的数量级.ORACLE8以后推出了分区选项.分区将表分离在若于不同的表空间上,用分而治之的方法来支撑元限膨胀的 ...

  2. oracle正确使用索引,通过案例学调优之--Oracle中null使用索引

    通过案例学调优之--Oracle中null使用索引 默认情况下,Oracle数据库,null在Index上是不被存储的,当在索引列以"is null"的方式访问时,无法使用索引:本 ...

  3. Oracle 的原理: 索引

    在表上建立索引,索引对于表,就像目录对于书一样,有了索引可以直接定位到表中的数据位置,大大的加快查找速度.索引可以减少磁盘IO,在逻辑上和物理上都独立于表的数据,索引可以存放在任何磁盘上面,此外Ora ...

  4. oracle数据库中索值,Oracle数据库中的索引详解

    Oracle数据库中的索引详解以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一 ROWID的概念 存储了row在数据文 ...

  5. 分析Oracle有时会用索引来查找数据的原因-oracle执行计划

    http://www.webjx.com/database/oracle-140.html 问:为什么Oracle有时会用索引来查找数据? 答:在你运用SQL语言,向数据库发布一条查询语句时,Orac ...

  6. Oracle有使用某个索引吗?(如何监控)

    Oracle有使用某个索引吗?(如何监控) Does Oracle use my index or not? One can use the index monitoring feature to c ...

  7. oracle_sqlserver和mysql获取表外键的方法_mysql、sqlserver、oracle三种数据库维护索引、外键、字段语法总结...

    mysql.sqlserver.oracle三种数据库维护索引.外键.字段语法总结 1.     MYSQL数据库 1)    创建索引 CREATE INDEX index_name ON tabl ...

  8. 深入学习Oracle分区表及分区索引

    关于分区表和分区索引(About Partitioned Tables and Indexes)对于10gR2而言,基本上可以分成几类: ?       Range(范围)分区 ?       Has ...

  9. oracle表重命名 索引,CSS_在Oracle数据库中按用户名重建索引的方法,如果你管理的Oracle数据库下某 - phpStudy...

    在Oracle数据库中按用户名重建索引的方法 如果你管理的Oracle数据库下某些应用项目有大量的修改删除操作, 数据索引是需要周期性的重建的. 它不仅可以提高查询性能, 还能增加索引表空间空闲空间大 ...

最新文章

  1. from torch._C import * ImportError: DLL load failed 动态链接库(DLL)初始化例程失败
  2. HTML5的 input:file上传类型控制
  3. Python中的sorted函数以及operator.itemgetter函数
  4. (2)stm32开发之使用Keil MDK以及标准外设库创建STM32工程
  5. 客户说发货慢怎么回复_?沐言恋爱学:当女生说“我累了”,怎么回复最合适?...
  6. mysql temporary_mysql – 如何在同一个查询中多次引用TEMPORARY表?
  7. 电子助力方向机控制模块_17款路虎揽胜:偶发性电子助力失效
  8. 【报告分享】2019年用户生命周期运营白皮书(京东尼尔森出品).pdf(附下载链接)
  9. redis缓存雪崩、缓存穿透和缓存击穿等总结
  10. python 消息中间件_如何评价腾讯开源的消息中间件TubeMQ?
  11. Windows Embedded 7 最简便EWF系统制作方案
  12. 如何在线伪造邮箱发件人,用任意邮箱发送邮件
  13. 有效利用PLM系统能为企业带来什么?
  14. 如何创建属于你自己的域名邮箱
  15. h5微信f分享链接给对方获取对方手机号_免费微信电子贺卡制作|微请柬
  16. mysql 关闭远程_禁止MySQL root远程访问
  17. CH582M,PWM模拟DAC实现WAV播放,FATFS文件
  18. Vulkan层的简要说明
  19. 「经济读物」小狗钱钱
  20. 示波器测量汽车进气压力传感器信号及波形分析

热门文章

  1. 话里话外:“按单制造”的业务特点(一)
  2. SMTP 队列邮件对照表
  3. Caused by: java.net.BindException: Could not start rest endpoint on any port in port range 8085
  4. 菜鸟教程中Java语法(Java教程+Java面向对象)
  5. AWK命令进行字符串替换-图解两个例子(转)
  6. intellij2018修改代码背景颜色
  7. TypeError: 'dict' object is not callable
  8. Html爱情表白动画
  9. 顺序执行_执行流程 | 你真的了解Spring AOP的执行顺序吗?
  10. Parse Fatal Error at line 4 column 43: 已经为元素 web-app 指定属性 xmlns。