重庆思庄Oracle、KingBase、PostgreSQL、Redhat认证学习论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 110|回复: 0
打印 上一主题 下一主题

[Oracle] oracle数据库索引掉了与失效的排查办法

[复制链接]
跳转到指定楼层
楼主
发表于 7 天前 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
但在具体排查之前,需要先明确你所说的“索引掉了”具体是指哪一种情况?

在 Oracle 数据库中,通常有以下三种情况会被大家称为“索引掉了”:

物理删除: 索引被彻底删除了(执行了 DROP INDEX)。

状态失效: 索引还在数据库里,但状态变成了不可用(UNUSABLE)。

执行计划改变(不走索引): 索引完好无损,但是 SQL 查询突然不再使用这个索引了(全表扫描)。

针对这三种情况,排查方法各不相同:

情况一:索引被物理删除了 (DROP INDEX)
如果有人或程序误删了索引,你可以通过以下几种方式来追查“凶手”和时间:

查看回收站 (Recycle Bin)
如果数据库开启了回收站,且删除时没有加 PURGE,被删除的索引会留在回收站中。

SQL
SELECT OBJECT_NAME, ORIGINAL_NAME, DROPTIME
FROM DBA_RECYCLEBIN
WHERE TYPE = 'INDEX' AND ORIGINAL_NAME = '你的索引名';
查看审计日志 (Audit Trail)
如果数据库开启了 DDL 审计(这是排查最准确的方法),可以查到是谁、在什么时间、从哪台机器执行了删除操作。

SQL
   SELECT USERNAME, OS_USERNAME, TERMINAL, TIMESTAMP, SQL_TEXT
   FROM DBA_AUDIT_TRAIL
   WHERE ACTION_NAME = 'DROP INDEX' AND OBJ_NAME = '你的索引名';
查询历史会话 (ASH / AWR)
如果删除操作发生在近期,可以通过 ASH 视图查找曾经执行过 DROP 语句的会话记录。

SQL
   SELECT SAMPLE_TIME, USER_ID, SQL_OPCODE, SQL_TEXT
   FROM DBA_HIST_ACTIVE_SESS_HISTORY h
   JOIN DBA_HIST_SQLTEXT t ON h.SQL_ID = t.SQL_ID
   WHERE UPPER(t.SQL_TEXT) LIKE '%DROP INDEX%你的索引名%';
使用 LogMiner 挖掘日志
如果没有开启审计,且历史记录已被冲掉,最后的杀手锏是使用 LogMiner 去解析 Oracle 的归档日志 (Archive Logs)。这可以 100% 还原出执行 DROP INDEX 的准确时间和相关事务,但操作相对复杂。

情况二:索引状态失效 (UNUSABLE)
如果索引还在,但是查询报错或者变慢,可能是索引失效了。

1. 确认索引状态:

SQL
SELECT INDEX_NAME, STATUS, LAST_ANALYZED
FROM DBA_INDEXES
WHERE INDEX_NAME = '你的索引名';
如果 STATUS 显示为 UNUSABLE,说明索引失效。

2. 常见原因排查:

表结构维护操作: 最近是否有人对表执行了 ALTER TABLE ... MOVE 改变了数据的物理存储位置?(这会导致所有普通索引失效)。

分区表操作: 如果是分区表,近期是否执行了 DROP PARTITION、TRUNCATE PARTITION 或 SPLIT PARTITION,且没有加上 UPDATE GLOBAL INDEXES 子句?(这会导致全局索引失效)。

直接路径加载: 是否使用了 SQL*Loader 的直接路径加载,或者执行了 INSERT /*+ APPEND */ ... 且中间发生了异常中断?

解决办法:
重建索引即可恢复:ALTER INDEX 你的索引名 REBUILD; (如果是分区索引可能需要 REBUILD PARTITION)。

情况三:SQL 突然不走索引了(执行计划改变)
这是最常见的“性能故障”,通常不是索引坏了,而是 Oracle 的优化器 (CBO) “认为”不走索引更快。

常见原因排查:

统计信息过期或突变:
表的数据量是否发生了剧增或大批量删除?使用以下语句查看表和索引最近一次收集统计信息的时间:

SQL
   SELECT TABLE_NAME, NUM_ROWS, LAST_ANALYZED FROM DBA_TABLES WHERE TABLE_NAME = '你的表名';
   SELECT INDEX_NAME, LAST_ANALYZED FROM DBA_INDEXES WHERE TABLE_NAME = '你的表名';
解决思路:重新收集统计信息 EXEC DBMS_STATS.GATHER_TABLE_STATS(...)
2. 隐式类型转换:
比如你的索引列是 VARCHAR2 类型,但是 SQL 里写的是 WHERE col = 123(传了数字类型)。Oracle 会在内部套用 TO_NUMBER() 函数,导致索引失效。
3. 在索引列上使用了函数:
如 WHERE TRUNC(create_time) = SYSDATE,除非你建了基于函数的索引,否则普通索引会失效。
4. 数据倾斜与绑定变量窥探 (Bind Peeking):
某个特定值的查询返回了表中大部分数据(比如状态位查询),Oracle 在第一次硬解析时“窥探”到了这个值,认为走全表扫描成本更低,并把这个执行计划缓存了下来,导致后续查小量数据的变量也被迫走全表扫描。

总结建议
你可以先执行一句简单的查询确认现状:

SQL
SELECT INDEX_NAME, INDEX_TYPE, STATUS
FROM USER_INDEXES
WHERE TABLE_NAME = '你的表名';
先看看它在不在,再看看它有没有失效 (STATUS)。

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 支持支持 反对反对
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|重庆思庄Oracle、Redhat认证学习论坛 ( 渝ICP备12004239号-4 )

GMT+8, 2026-5-24 12:07 , Processed in 0.198354 second(s), 19 queries .

重庆思庄学习中心论坛-重庆思庄科技有限公司论坛

© 2001-2020

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