ORACLE索引失效的问题分析

摘要

索引失效原因, 在SQL*LOADER 加载过程中会维护索引,由于数据量比较大,在SQL*LOADER 加载过程中出现异常情况,导致ORACLE 来不及维护索引,导致索引处于失效状态,影响查询和加载。

一、问题情景

2月16日现场同事发现某个tablespace空间快要耗尽,让我们手工清楚些数据,腾出足够空间,等用户有预算添加磁盘。该问题年前已经处理过一次,我们已经将数据保留期限做了缩减,按道理不会这么快出现磁盘空间耗尽的情况。我猜测可能是自动分区程序没有运行,没有自动删除旧分区,而新数据又不断产生,导致磁盘空间被逐渐耗尽。

看出从2011-02-02开始到16号这段时间分区维护没有执行,导致空间满。

于是通知集成组同事运行自动分区维护程序。

自动分区维护运行后,空间使用率低于80%了。问题解决了。

过了1小时,现场同事又反映采集程序卡住不动了,让我们赶紧核查原因,排除故障,给出故障报告。

二、问题分析

首先想到的是不是哪个表被锁住了。

select * from v$locked_object t1,user_objects t2
where t1.object_id=t2.object_id

通过语句查到,确实有很多相关表被锁住了。

继续查是哪些语句锁住了表

select sid,
       v$session.username 用户名,
       last_call_et 持续时间,
       status 状态,
       LOCKWAIT 等待锁,
       machine 用户电脑名,
       logon_time 开始登入时间,
       sql_text
from v$session, v$process, v$sqlarea
where paddr = addr
   and sql_hash_value = hash_value 
   and status = 'ACTIVE'
   and v$session.username is not null
order by last_call_et desc;

发现有个delete语句在执行,该delete语句为:

delete from table1 where column1=? and column2=? and column3=?

看该语句的执行计划,发现是全表扫描,没有走索引。

我们估计是不是索引失效了

select status,T.* from user_indexes T
where table_name='TABLE1'

发现status='INVALID'失效。

重建该索引:

drop index ......
create index ......

问题解决。

是什么问题导致的索引失效呢?该问题是运行分区维护后发生的,于是把该问题转给了开发自动分区管理的同事了。该问题后续再补充。

三、知识点总结

1.如何判断和确认索引失效?

通过查看user_indexes的status来确定用户索引状态。

分区索引查看DBA_IND_PARTITIONS的status来确定。

2.重建索引的方式有哪些,有什么区别?

1)drop index...和create index

2)alter index idx_name rebuild

3)alter index idx_name rebuild online

a)rebuild会阻塞对基表的DML操作,但不会影响rebuild期间查询对原有索引的使用。
b)rebuild的数据源可能是基表,也可能是原索引。取决于基表和原索引的大小,哪个小,rebuild时就会用哪个作为数据源。

c)rebuild online运行用户在索引重建期间执行DML操作。
d)rebuild online的数据源是基表。

3.导致索引失效的原因有哪些?原因:当某些操作导致数据的rowid改变,索引就会完全失效。

那什么时候会导致rowid改变使得索引unuseable或者invalid呢?

一般普通表在在如下3个情况下可以使index unusable
1)move  【alter table move】【alter table t02 move tablespace tbs01;】
2)sqlldr 【sqlldr ( parallel or direct )append 】【sqlldr direct=y + 主键重复】

3)手动alter index unusable

对分区表,又要分local index和global index来说
1)首先上面的导致普通表上的索引失效的原因对分区表也同样适用.
2)对local index在exchange without including indexes的时候也会unusable
3)global index在partition mt的时候会导致unusable[除非加上update global indexes]

以下为引用:

1.导致的原因: 
   在SQL*LOADER 加载过程中会维护索引,由于数据量比较大,在SQL*LOADER 加载过程中出现异常情况,导致ORACLE 来不及维护索引,导致索引处于失效状态,影响查询和加载。 异常情况主要有:在加载过程中杀掉SQL*LOADER 进程,重启,表空间不够等。

2.  global索引,当global 索引所在表执行alter table 涉及下列操作时,会导至该索引失效:

? ADD PARTITION | SUBPARTITION

? COALESCE PARTITION | SUBPARTITION

? DROP PARTITION | SUBPARTITION

? EXCHANGE PARTITION | SUBPARTITION

? MERGE PARTITION | SUBPARTITION

? MOVE PARTITION | SUBPARTITION

? SPLIT PARTITION | SUBPARTITION

? TRUNCATE PARTITION | SUBPARTITION

因此,建议用户在执行上述操作sql 语句后附加update indexes 子句,oracle 即会自动维护全局索引。

3. 执行alter table 时未指定update indexes 子句:

如果是range/list 分区,其local 索引和global 索引不会受影响;

如果是hash 分区,新加分区及有数据移动的分区的local 索引和glocal 索引会被置为unuseable,

需要重新编译

对于分区表中索引失效要重建索引

select 'alter index '||t.index_name||' rebuild partition '||t.partition_name from user_ind_partitions t where t.index_name='IDX_PART2'  and t.status='unusable'

查出来后,在命令窗口执行。查出来的语句就可以了


IT家园
IT家园

网友最新评论 (0)