设为首页 收藏本站
查看: 931|回复: 0

[经验分享] 如何让ORACLE索引不起作用(不可见)

[复制链接]
YunVN网友  发表于 2016-8-13 06:46:47 |阅读模式
如何让ORACLE索引不起作用(不可见)

  
  我们经常在数据库上建索引或删除索引,由于索引对SQL的执行性能影响非常大,有可能变得很好,也有可能变得很差,在线下开发环境我们可以充分测试,对于创建或删除索引没什么问题。但是在线上环境,由于高并发的访问,如果我们删除了一个重要的大索引(GB以上),删除后才发现大量SQL性能变差,很快主机就LOAD飙升,系统无法运行了,由于索引已经删除,并且很大,要当场重建基本不可能,因为这个索引巨大,创建估计要几分钟甚至几个小时,况且这时主机已经基本没有响应,IO全部用光,只能把应用停了,等索引建好后再开始打开应用,等发生这样的事才会为自己的失误而后悔。那我们有没有办法让删除索引的风险降低呢,请看下文:
  
  我们先创建一个表t1,在t1的table_name字段上新建一个索引idx_t1_table_name。
  create table t1 as select * from all_tables;--创建表create index idx_t1_table_name on t1(table_name); --创建索引analyze table t1 compute statistics; --收集表的统计信息用执行计划验证索引是否有效SQL> explain plan for select count(*) from t1 where table_name='DUAL';ExplainedSQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);PLAN_TABLE_OUTPUT----------------------------------------------------------------------------------------------------------------------------------------------------------------| Id  | Operation            |  Name              | Rows  | Bytes | Cost (%CPU)|--------------------------------------------------------------------------------|   0 | SELECT STATEMENT     |                    |     1 |    17 |     2  (50)||   1 |  SORT AGGREGATE      |                    |     1 |    17 |            ||*  2 |   INDEX RANGE SCAN   | IDX_T1_TABLE_NAME  |     2 |    34 |     2  (50)|--------------------------------------------------------------------------------
  
  OK,从上面我们可以看到索引很正常。那现在假设我们不再需要这个索引了,因此想删除它,但又不知道会不会有本文开头所说的风险。如果可以删除前先把索引不可见,确认没问题后再删除,这样就没问题了,为此,Oracle11g推出新的功能,设置索引是否可见,示例如下:
  SQL> alter index IDX_T1_TABLE_NAME invisible;Index alteredSQL>  explain plan for select count(*) from t1 where table_name='DUAL';ExplainedSQL>  SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);PLAN_TABLE_OUTPUT-------------------------------------------------------------------------| Id  | Operation            |  Name       | Rows  | Bytes | Cost (%CPU)|-------------------------------------------------------------------------|   0 | SELECT STATEMENT     |             |     1 |    17 |    23  (22)||   1 |  SORT AGGREGATE      |             |     1 |    17 |            ||*  2 |   TABLE ACCESS FULL  | T1          |     2 |    34 |    23  (22)|-------------------------------------------------------------------------这样索引就隐藏起来了,如果把索引隐藏后发现有性能问题,我们可以立即打开索引:SQL> alter index IDX_T1_TABLE_NAME visible;Index alteredSQL> explain plan for select count(*) from t1 where table_name='T1';ExplainedSQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------Plan hash value: 3098159--------------------------------------------------------------------------------| Id  | Operation         | Name              | Rows  | Bytes | Cost (%CPU)| Tim--------------------------------------------------------------------------------|   0 | SELECT STATEMENT  |                   |     1 |    17 |     1   (0)| 00:|   1 |  SORT AGGREGATE   |                   |     1 |    17 |            ||*  2 |   INDEX RANGE SCAN| IDX_T1_TABLE_NAME |     1 |    17 |     1   (0)| 00:--------------------------------------------------------------------------------
  
  以上是Oracle11g的处理方法,但是在Oracle9i或Oracle10g中索引没有invisible的功能,我们如何处理呢?
现在Oracle数据库一般都采用基于成本的计算方法来生成执行计划,只要索引的成本更低,ORACLE就会选择使用索引,OK,那我们只要告诉ORACLE使用这个索引成本很高,它就不会使用这个索引,这样就达到了暂时让索引不可用的效果。相信很多人都知道ORACLE提供了dbms_stats包来管理对像的统计信息,通过dbms_stats.set_index_stats函数我们可以强制设置统计信息,现在我们只要把索引的成本设置成非常大即可,如下所示:
  --查看IDX_T1_TABLE_NAME的基本统计信息SQL> select a.owner,a.index_name,a.blevel,a.leaf_blocks,a.num_rows from all_indexes a where owner='YZS' and index_name='IDX_T1_TABLE_NAME';OWNER                          INDEX_NAME                         BLEVEL LEAF_BLOCKS   NUM_ROWS------------------------------ ------------------------------ ---------- ----------- ----------YZS                            IDX_T1_TABLE_NAME                       1          12       2710--设置非常离谱的统计信息,让ORACLE认为使用索引的成本很高SQL> exec dbms_stats.set_index_stats(ownname => 'YZS',indname => 'IDX_T1_TABLE_NAME',indlevel => 10,numlblks => 1000000000,numrows => 100000000000,no_invalidate => false );PL/SQL procedure successfully completed备注:indlevel值不能设置太高,有些版本的ORACLE有BUG,会导致SQL解析发生错误。numlblks的值也不用太大,因为ORACLE统计信息里索引的块数最高也只能是4294967295。 no_invalidate=false表示让CACHE中的执行计划立即失效,重新按现在的统计信息生成SQL执行计划。--验证一下是否生效SQL> explain plan for select count(*) from t1 where table_name='DUAL';ExplainedSQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------Plan hash value: 3724264953---------------------------------------------------------------------------| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |---------------------------------------------------------------------------|   0 | SELECT STATEMENT   |      |     1 |    19 |    30   (0)| 00:00:01 ||   1 |  SORT AGGREGATE    |      |     1 |    19 |            |          ||*  2 |   TABLE ACCESS FULL| T1   |     1 |    19 |    30   (0)| 00:00:01 |---------------------------------------------------------------------------OK,现在已经看到了,没有使用索引,那如果我们发现修改统计信息后一些SQL性能变差,我们可以把索引的真实的统计信息还原即可,如下所示:SQL> exec dbms_stats.set_index_stats(ownname => 'YZS',indname => 'IDX_T1_TABLE_NAME',indlevel => 1,numlblks => 12,numrows => 2710,no_invalidate => false );PL/SQL procedure successfully completedSQL> explain plan for select count(*) from t1 where table_name='DUAL';ExplainedSQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------Plan hash value: 3098159--------------------------------------------------------------------------------| Id  | Operation         | Name              | Rows  | Bytes | Cost (%CPU)| Tim--------------------------------------------------------------------------------|   0 | SELECT STATEMENT  |                   |     1 |    19 |     1   (0)| 00:|   1 |  SORT AGGREGATE   |                   |     1 |    19 |            ||*  2 |   INDEX RANGE SCAN| IDX_T1_TABLE_NAME |     1 |    19 |     1   (0)| 00:--------------------------------------------------------------------------------这样我们就快速还原回开始时的状态,不会再发生悲剧了。
  
  使用统计信息骗Oracle不使用索引的方法是偏门,如果是Oracle11g 建议还是直接使用invisible更好。
为了更好的进行索引管理,Oracle还提供了索引监视的功能,这样可以准确的确认索引还有没有使用。语法如下:
  --打开索引监视SQL> alter index IDX_T1_TABLE_NAME monitoring usage;Index alteredSQL> select * from v$object_usage where INDEX_NAME='IDX_T1_TABLE_NAME';INDEX_NAME                     TABLE_NAME                     MONITORING USED START_MONITORING    END_MONITORING------------------------------ ------------------------------ ---------- ---- ------------------- -------------------IDX_T1_TABLE_NAME              T1                             YES        NO   05/28/2011 22:01:26 --USED字段表示这个索引有没有使用过SQL> select count(*) from t1 where table_name='DUAL';COUNT(*)----------1SQL> select * from v$object_usage where INDEX_NAME='IDX_T1_TABLE_NAME';INDEX_NAME                     TABLE_NAME                     MONITORING USED START_MONITORING    END_MONITORING------------------------------ ------------------------------ ---------- ---- ------------------- -------------------IDX_T1_TABLE_NAME              T1                             YES        YES  05/28/2011 22:01:26 --停止监视SQL> alter index IDX_T1_TABLE_NAME nomonitoring usage;Index altered
  
  
MKing

2011-05-29

我的新浪微博http://weibo.com/yzsind

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-256963-1-1.html 上篇帖子: 关于Oracle 01122,01110,01207的错误和解决 下篇帖子: oracle与mysql在sql语句上的区别
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表