1.4. 删除重复的索引

查找重复的索引

select  *

    from

( select    index_owner,

index_name,

table_owner,

table_name,

             max(decode(p, 1,     c,NULL)) ||

             max(decode(p, 2,', '||c,NULL)) ||

             max(decode(p, 3,', '||c,NULL)) ||

             max(decode(p, 4,', '||c,NULL)) ||

             max(decode(p, 5,', '||c,NULL)) ||

             max(decode(p, 6,', '||c,NULL)) ||

            max(decode(p, 7,', '||c,NULL)) ||

             max(decode(p, 8,', '||c,NULL)) ||

            max(decode(p, 9,', '||c,NULL)) ||

            max(decode(p,10,', '||c,NULL)) ||

            max(decode(p,11,', '||c,NULL)) ||

            max(decode(p,12,', '||c,NULL)) ||

            max(decode(p,13,', '||c,NULL)) ||

            max(decode(p,14,', '||c,NULL)) ||

            max(decode(p,15,', '||c,NULL)) ||

            max(decode(p,16,', '||c,NULL)) index_cols

       from (select index_owner,index_name,table_owner,table_name, substr(column_name,1,30) c, column_position p

                  from dba_ind_columns )

      group by index_owner,index_name,table_owner,table_name  ) A,

   ( select index_owner,

index_name,

table_owner,

table_name,

             max(decode(p, 1,     c,NULL)) ||

            max(decode(p, 2,', '||c,NULL)) ||

            max(decode(p, 3,', '||c,NULL)) ||

            max(decode(p, 4,', '||c,NULL)) ||

            max(decode(p, 5,', '||c,NULL)) ||

            max(decode(p, 6,', '||c,NULL)) ||

            max(decode(p, 7,', '||c,NULL)) ||

            max(decode(p, 8,', '||c,NULL)) ||

            max(decode(p, 9,', '||c,NULL)) ||

            max(decode(p,10,', '||c,NULL)) ||

            max(decode(p,11,', '||c,NULL)) ||

            max(decode(p,12,', '||c,NULL)) ||

            max(decode(p,13,', '||c,NULL)) ||

            max(decode(p,14,', '||c,NULL)) ||

            max(decode(p,15,', '||c,NULL)) ||

            max(decode(p,16,', '||c,NULL)) index_cols

       from (select index_owner,index_name,table_owner,table_name, substr(column_name,1,30) c, column_position p

                  from dba_ind_columns )

      group by index_owner,index_name,table_owner,table_name  ) B

   where a.table_owner=b.table_owner

and a.table_name=b.table_name

and (a.index_owner<>b.index_owner

or a.index_name <> b.index_name )

and a.index_cols like b.index_cols || '%'

and a.owner not in (‘SYS’,’SYSTEM’,’OUTLN’,’WMSYS’ ) 

and a.table_name not like '%$%'

 

出来的结果中,排在后面的索引是可以删除的。

 

 

1.5. 做为一项常规任务,每个月做一次停下应用的维护

检查哪些表碎片比较多,对这些碎片很多的表做 move ,同时将失效的索引全部重建。

这一项任务是在已经对表都做了分析的情况下来做。

 

做 scrīpt0 ,对表全部做分析

begin

dbms_stats.gather_schema_stats (‘JZ21’ );

end;

/

 

针对所有的 schema 都做一次。

 

-- 查看哪些表的空间碎片比较大,目前是认为大于 30% 就做整理。

select * from (

Select owner,table_name,(num_rows*avg_row_len/8000),blocks,

(num_rows*avg_row_len/8000)/( decode(blocks,0,1,null,1,blocks)) bb

from dba_tables where owner in (‘JZ21’) 

and TEMPORARY=’N’

) tt

where tt.bb<0.7 and blocks>10;

 

-- 生成整理脚本 scrīpt1

select ‘alter table ‘||owner||’.’||table_name||’ move; ’ from (

Select owner,table_name,(num_rows*avg_row_len/8000),blocks,

(num_rows*avg_row_len/8000)/( decode(blocks,0,1,null,1,blocks)) bb

from dba_tables where owner in (‘JZ21’) 

and TEMPORARY=’N’

) tt

where tt.bb<0.7 and blocks>10;

 

-- 预备好分析脚本,不过这个脚本应该最后做 scrīpt3

select 'exec dbms_stats.gather_table_stats( '''||owner||''','''||table_name||''' ,method_opt => ''for all columns'', cascade => true ); ' from (

Select owner,table_name,(num_rows*avg_row_len/8000),blocks,

(num_rows*avg_row_len/8000)/( decode(blocks,0,1,null,1,blocks)) bb

from dba_tables where owner in (‘JZ21’) 

and TEMPORARY='N'

) tt

where tt.bb<0.7 and blocks>10;

 

 

-- 生成重建索引脚本 scrīpt2

select ‘alter index ‘||owner||’.’||index_name||’ rebuild nologging;’ from dba_indexes where owner in (‘JZ21’)  and status='UNUSABLE' ;

 

步骤: 先执行 scrīpt0

结束后,生成 scrīpt1,scrīpt2,scrīpt3

按顺序执行, scritp1,scrīpt2,scrīpt3 。

 

 

1.6. 特殊情况下对数据库重新整理

1.6.1.     对表做 move

alter table test_move move ;

 

  select ‘alter table ‘||owner||’.’||table_name||’ move; ’  from dba_tables where owner in (‘JZ21’ )  and TEMPORARY=’N’;

 

这里用需要做 move 的 schema 替换。

 

1.6.2.     对 index 做 rebuild

alter INDEX idx_test_move rebuild nologging;

 

select ‘alter index ‘||owner||’.’||index_name||’ rebuild nologging;’ from dba_indexes where owner in (‘JZ21’);

 

 

1.6.3.     对所有的表做分析

 

begin

dbms_stats.gather_schema_stats (‘JZ21’ );

end;

/

 

针对所有的 schema 都做一次。

 

1.7. 对索引打开监视开关,看哪些索引没有被使用( 慎用)

select ‘alter index ‘||owner||’.’||index_name||’ monitoring usage;’ from dba_indexes

where owner not in (‘SYS’,’SYSTEM’ );

 

在运行了一个很完整的周期以后 ( 对我们来说,例如 2 个完整的交易日 ) ,检查有哪些索引没有被使用

 

select index_name,monitoring,used,start_monitoring,end_monitoring from v$object_usage

where used='NO';

如果这些索引不是主键或唯一索引,一般情况下这些索引可以去掉。

 

检查完一次以后,将索引监视关闭,不需要老是监视索引的使用:

select ‘alter index ‘||owner||’.’||index_name||’ nomonitoring usage;’ from dba_indexes where owner in (‘WHT’);

2.   语句调优

2.1. PL/SQL 中的语法解释工具

语句的执行效率是否符合需要,一个是简单的把语句提取出来直接执行一下,看效果如何,但很多情况下,语句的运行是根据实际的条件运行的,所以有时候我们写完语句有要先分析一下语句是否是最优的,这时候我们就可以用PL/SQL 的 explain 窗口(或直接选种语句后,按 F5 ),有时侯,我们已知语句比较慢,要寻找为什么会慢,也可以如此做。

在 EXPLAIN 窗口,我们需要关注几个重要的东西, COST (成本),如果这个 COST 数字很大,说明语句效率不高,需要想办法;有无 TABLE ACCESS FULL ,如果有,只要数据量大一些,效率就不会高。我们要尽量避免产生table access full, 方法之一就是建索引,另一个方法是改写连接方式,使能够用到索引。另一个需要关注的是 join 方式,nest loops outer 和 hash join outer ,这两种方式的效果是不一样的,有时有天壤之别,目前我没有类似的经验可以写,以后碰到后补充。

2.2. ORACLE 提供的调优工具

ORACLE 本身提供了很好的客户端的性能调试和跟踪工具。 ORACLE 的工具非常好,可以帮助我们很容易的找到系统性能的瓶颈语句在哪里。 ORACLE 性能调整工具的位置在:

开始 — 程序 —Oracle – Orahome92 – Enterprise Management Packs –Diagnostics –Performance Manager ,登陆后找到数据库栏,然后连接就可以看到。

我常用其中的两项来调整性能(其他 的也很有用处):一,顶层会话;二, SQL ,分别做介绍。