INSERT慢主因是日志机制而非SQL质量;需设表NOLOGGING、禁用/重建索引为NOLOGGING,并确认未启用FORCE LOGGING,否则APPEND无效。

INSERT慢不是SQL写得差,而是日志机制在拖后腿
Oracle默认所有DML操作都强制生成完整redo log和undo log,哪怕只是往空表里插10万行——这跟语句本身关系不大,本质是事务安全机制的代价。真正卡住的环节通常是user_io_wait等待,尤其当目标表是大分区表(比如BASE_FMLG有15亿行)、且处于归档模式时,日志刷盘+归档同步会吃掉绝大部分时间。
/*+ APPEND */必须配合NOLOGGING才有效
单独加/*+ APPEND */提示只启用“直接路径插入”,跳过buffer cache、直接写数据文件;但若表仍是LOGGING状态,Oracle仍会为每条新数据块生成大量redo。只有表属性设为NOLOGGING,才能让APPEND真正生效:
-
ALTER TABLE BASE_FMLG NOLOGGING;—— 必须在INSERT前执行,且对已有数据无效 -
INSERT /*+ APPEND */ INTO BASE_FMLG SELECT * FROM TEMP_FMLG_PURGE;—— 注意:不能带VALUES子句,只能是SELECT形式 - 如果表有主键/唯一约束,
APPEND会失败,需先DISABLE CONSTRAINT
索引才是隐藏的redo大户
很多人以为设了NOLOGGING就万事大吉,结果发现速度没提升多少——问题出在索引上。即使表不记日志,每次插入仍要更新所有索引,而INDEX默认仍是LOGGING,照样狂打redo:
- 最彻底做法:
ALTER INDEX IDX_NAME UNUSABLE;,插入完再REBUILD - 重建索引时也加
NOLOGGING:ALTER INDEX IDX_NAME REBUILD NOLOGGING PARALLEL 4; - 如果索引字段极少变动,可直接建为
NOLOGGING:CREATE INDEX ... NOLOGGING;
归档模式下NOLOGGING不等于零风险
NOLOGGING操作在归档模式下仍会生成极少量redo(仅用于数据文件头、段头等元信息),但关键点在于:这些操作不可恢复。一旦发生介质故障,NOLOGGING写入的数据块无法通过归档日志还原:
- 仅限非生产环境或可重跑场景(如每日ETL临时表加载)
- 生产环境若必须用,务必在
INSERT后立即做一次RMAN全量或增量备份 - 确认数据库未开启
FORCE LOGGING(查SELECT force_logging FROM v$database;,返回YES则NOLOGGING被强制覆盖)
实际调优中,最常被忽略的是索引状态和FORCE LOGGING开关——这两项不处理,光改APPEND和NOLOGGING基本白忙。











