Oracle基础,在每次批量插入前禁用索引、插入后重建,这种操作模式虽然能解决 ORA-26028 问题并利用直接路径插入的性能优势,但确实会对数据库产生多方面的影响,需要仔细权衡。
这是一个非常好的问题。在每次批量插入前禁用索引、插入后重建,这种操作模式虽然能解决 ORA-26028 问题并利用直接路径插入的性能优势,但确实会对数据库产生多方面的影响,需要仔细权衡。
以下是主要的影响和风险:
1. 系统资源消耗巨大
CPU 和 I/O 压力:
- 重建索引是一个非常消耗 CPU 和 I/O 的操作。Oracle 需要扫描表数据、排序、构建新的 B-Tree 结构,并写入新的数据块。
- 对于大表上的大索引,重建过程可能持续数分钟甚至数小时,期间会占用大量系统资源,可能影响其他业务的正常运行。
内存压力:
- 索引重建需要在 PGA(进程全局区)中进行排序操作,如果索引很大,会消耗大量内存。
2. 锁和阻塞问题
表级锁(DML 锁):
- 在执行
ALTER INDEX ... REBUILD时,Oracle 通常会对相关的表加共享锁(S 锁)或排他锁(X 锁),这取决于重建方式和索引类型。 - 在此期间,其他会话可能无法对表执行 DML 操作(INSERT/UPDATE/DELETE),导致业务阻塞。
- 在执行
长时间操作:
- 重建大索引耗时较长,意味着锁持有时间也长,增加了业务停顿的风险。
3. 可用性降低
索引不可用窗口期:
- 从
UNUSABLE到REBUILD完成之间,索引处于失效状态。 - 在此期间,任何依赖该索引的查询都会退化为全表扫描,性能急剧下降,可能导致关键查询超时或系统响应变慢。
- 从
失败风险:
- 如果重建过程中因空间不足、I/O 错误等原因失败,索引将保持
UNUSABLE状态,影响所有相关查询,需要人工干预。
- 如果重建过程中因空间不足、I/O 错误等原因失败,索引将保持
4. 存储空间临时翻倍
- 重建机制:
- Oracle 重建索引时,会先创建一个新的索引段,待新索引构建完成后,再删除旧的索引段。
- 这意味着在重建过程中,索引需要双倍的存储空间。
- 如果表空间空间不足,重建操作会失败,报
ORA-01652(无法扩展临时段)或类似错误。
5. 维护窗口和计划复杂性
必须安排维护窗口:
- 由于资源消耗大、有锁和可用性风险,这种操作通常只能在业务低峰期(如夜间)执行。
- 增加了运维的复杂性和对业务的影响。
脚本复杂性:
- 需要编写健壮的脚本,包含错误处理、状态检查、日志记录等,否则容易出错。
更优的替代方案
为了避免上述问题,建议考虑以下更优的实践:
✅ 方案一:分区交换(Partition Exchange)—— 推荐!
- 原理:将数据先加载到一个临时表(或空分区),然后通过
ALTER TABLE ... EXCHANGE PARTITION快速交换。 - 优点:
- 交换操作是元数据级别的,几乎瞬间完成(毫秒级)。
- 不会导致全局索引失效(使用
WITHOUT VALIDATION选项)。 - 对业务影响极小,无需重建索引。
- 前提:主表必须是分区表。
✅ 方案二:仅对必要索引使用 APPEND,其他用常规插入
- 如果只有部分大索引受影响,可以考虑只对这些索引禁用/重建,或者评估是否可以接受部分数据用常规路径插入。
✅ 方案三:使用 APPEND + 批量重建,但减少频率
- 不要“每次插入”都重建,而是积累多个小批量插入,一次性重建。
- 或者使用 在线重建(
REBUILD ONLINE),允许在重建期间对表进行 DML 操作(但仍需注意资源消耗):
ALTER INDEX idx_name REBUILD ONLINE;总结
影响/维度具体表现
性能/重建时 CPU、I/O、内存消耗巨大
可用性/索引失效窗口期长,查询性能下降
稳定性/可能因空间不足或错误导致失败
存储/重建期间需要双倍索引空间
运维/需要维护窗口,脚本复杂
结论:频繁地“禁用 → 插入 → 重建”不是一个理想的长期策略,尤其对于大表和生产环境。它虽然解决了直接路径插入的问题,但引入了新的性能和可用性风险。
强烈建议:
- 优先考虑 分区表 + 分区交换 的架构。
- 如果无法分区,至少使用
REBUILD ONLINE并安排在低峰期执行。 - 做好监控,确保表空间和系统资源充足。
附:
由于某工具是用批量写入方式操作数据,每次写入后都会导致错误:
ORA-01502: 索引 'ENDBA.PK_ENJBPARAM' 或这类索引的分区处于不可用状态
--这个报错后,会再报K1_ENJBPARAM无法使用
插入新数据出错,插入失败,具体信息如下ORA-26028: 索引 ENDBA.K1_ENJBPARAM 在最初处于无法使用的状态
...
此时删除时也报错
delete from endba.enjbparam dd where dd.job_no='xxx'
ORA-01502: 索引 'ENDBA.PK_ENJBPARAM' 或这类索引的分区处于不可用状态
...
S提议先禁用,写入后再打开(实际上是重建)
查询资料确实是有这么做的,确实也是一种方法。
但考虑到频繁禁用打开索引,对数据库也不好。
【测试脚本】
select systimestamp from dual;
--测试一下重建索引
select systimestamp from dual;
ALTER INDEX endba.PK_enjbparam REBUILD;
select systimestamp from dual;
ALTER INDEX endba.k1_enjbparam REBUILD;
select systimestamp from dual;
--测试结束
select systimestamp from dual;
【测试结果】
SQL> select systimestamp from dual;
SYSTIMESTAMP
--------------------------------------------------------------------------------
30-10月-25 10.42.28.412000 上午 +08:00
SQL> --测试一下重建索引
SQL> select systimestamp from dual;
SYSTIMESTAMP
--------------------------------------------------------------------------------
30-10月-25 10.42.28.503000 上午 +08:00
SQL> ALTER INDEX endba.PK_enjbparam REBUILD;
Index altered
SQL> select systimestamp from dual;
SYSTIMESTAMP
--------------------------------------------------------------------------------
30-10月-25 10.43.08.151000 上午 +08:00
SQL> ALTER INDEX endba.k1_enjbparam REBUILD;
Index altered
SQL> select systimestamp from dual;
SYSTIMESTAMP
--------------------------------------------------------------------------------
30-10月-25 10.43.30.086000 上午 +08:00
SQL> --测试结束
SQL> select systimestamp from dual;
SYSTIMESTAMP
--------------------------------------------------------------------------------
30-10月-25 10.43.30.164000 上午 +08:00
...
PK主键用时:42.28-43.08,用了40秒
K1索引用时:43.08-43.30,用时22秒
用时太长了,所以这种方式不可行。
索引怎么可以这样频繁的重建呢,
本来主键索引就不能轻易的执行重建,尤其对于一些大表。
偶尔特殊的情况,这样操作一下尚可,
常规日常的处理,肯定不能这样操作的,
仅是个人理解。
end
Tag: Oracle基础