物化视图刷新(尤其fast或on commit)导致基表索引unusable是oracle 19c预期行为,主因是刷新中涉及分区交换、直接路径插入或truncate+append等操作触发b-tree索引失效;需通过user_indexes或user_ind_partitions定位并在线重建,automatic indexing不负责修复已失效索引。
oracle 19c 中物化视图刷新(尤其是 fast 刷新或基于 on commit 的刷新)后,其底层基表上的某些索引可能被标记为 unusable,这不是 bug,而是 oracle 内部维护一致性时的预期行为——特别是当刷新过程涉及分区交换、直接路径插入(insert /*+ append */)或 alter table move 类操作时,b-tree 索引会自动失效。
物化视图刷新为何导致索引 UNUSABLE
根本原因在于:Oracle 在执行某些快速刷新逻辑时,会临时重建物化视图日志或重写基表段(例如为保证原子性而使用交换分区),这些操作会触发关联索引进入 UNUSABLE 状态。常见场景包括:
-
DBMS_MVIEW.REFRESH调用中指定method => 'F'且基表存在本地分区索引(LOCAL) - 物化视图定义含
ROWID或PRIMARY KEY快速刷新机制,但基表索引未设为USING INDEX或未启用UPDATE INDEXES - 刷新前基表刚执行过
ALTER TABLE ... MOVE PARTITION,而索引未显式UPDATE INDEXES - 使用了
ATOMIC_REFRESH => FALSE,底层走的是TRUNCATE + INSERT /*+ APPEND */,这会让普通 B-tree 索引直接失效
如何确认哪些索引被影响
别猜,直接查。重点看当前用户下状态异常的索引,尤其注意是否属于物化视图基表:
SELECT index_name, table_name, status, partitioned
FROM user_indexes
WHERE status = 'UNUSABLE'
AND table_name IN (
SELECT mview_name FROM user_mviews
UNION
SELECT master FROM user_mview_logs
);
如果返回结果为空但性能明显下降,再检查 user_ind_partitions(对分区索引)或 dba_indexes(跨用户场景),避免漏掉子分区级失效。
配置自动重建脚本(安全在线重建)
手动逐个 ALTER INDEX ... REBUILD ONLINE 不现实,尤其在批量刷新后。下面这个 PL/SQL 块可嵌入作业或刷新后立即调用,它只重建当前用户下 UNUSABLE 的普通索引(跳过函数索引、位图索引等敏感类型),并带基础错误捕获:
BEGIN
FOR idx IN (
SELECT index_name
FROM user_indexes
WHERE status = 'UNUSABLE'
AND index_type = 'NORMAL'
AND temporary = 'N'
) LOOP
BEGIN
EXECUTE IMMEDIATE 'ALTER INDEX ' || idx.index_name || ' REBUILD ONLINE';
DBMS_OUTPUT.PUT_LINE('Rebuilt: ' || idx.index_name);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Failed on ' || idx.index_name || ': ' || SQLERRM);
END;
END LOOP;
END;
关键点:
- 加了
index_type = 'NORMAL'过滤,避免误触FBI或BITMAP索引(它们不支持ONLINE重建) - 没用
DBMS_PARALLEL_EXECUTE,因为索引重建本身已支持并行,靠ALTER INDEX ... REBUILD ONLINE PARALLEL 4更可控 - 生产环境建议包装成存储过程,并在
DBMS_SCHEDULER中设置失败重试(最多 2 次),避免单点失败阻塞后续流程 - 若需重建分区索引,请改查
user_ind_partitions并拼接ALTER INDEX ... REBUILD PARTITION ... ONLINE
Automatic Indexing 能不能接管这类失效索引
不能。Oracle 19c 的 DBMS_AUTO_INDEX 只管理「新建」和「删除」自动索引,以及将验证通过的候选索引从 INVISIBLE 变为 VISIBLE;它**不负责重建已存在的、人为创建但变 UNUSABLE 的索引**。即使你启用了 AUTO_INDEX_MODE = IMPLEMENT,也不会触发对 UNUSABLE 状态索引的修复动作。这点必须明确——自动索引 ≠ 自动修复索引。
真正容易被忽略的是:很多 DBA 以为开了 AUTOMATIC INDEXING 就一劳永逸,结果物化视图刷新后查询变慢,却去查执行计划里有没有用上 SYS_AI 开头的索引,而忘了先看 user_indexes.status 是不是满屏 UNUSABLE。











