Oracle
Allen 2025-10-30 0 1 0 0 0 0
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 状态,影响所有相关查询,需要人工干预。

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、内存消耗巨大
可用性/索引失效窗口期长,查询性能下降
稳定性/可能因空间不足或错误导致失败
存储/重建期间需要双倍索引空间
运维/需要维护窗口,脚本复杂

结论:频繁地“禁用 → 插入 → 重建”不是一个理想的长期策略,尤其对于大表和生产环境。它虽然解决了直接路径插入的问题,但引入了新的性能和可用性风险。

强烈建议:

  1. 优先考虑 分区表 + 分区交换 的架构。
  2. 如果无法分区,至少使用 REBUILD ONLINE 并安排在低峰期执行。
  3. 做好监控,确保表空间和系统资源充足。


附:

由于某工具是用批量写入方式操作数据,每次写入后都会导致错误:
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基础
欢迎评论
未登录,
请先 [ 注册 ] or [ 登录 ]
(一分钟即可完成注册!)
返回首页     ·   返回[Oracle]   ·   返回顶部