/*+ append_values */未生效或报错因不满足直接路径插入硬性条件:表有启用触发器、事务中已执行常规dml、为iot或被外键引用;此时oracle静默退化或抛ora-12838。

直接用 FORALL + /*+ APPEND_VALUES */ 是最常用且有效的组合,但必须满足表结构和事务环境条件,否则会静默退化或报 ORA-12838。
为什么 /*+ APPEND_VALUES */ 没生效甚至报错
它触发的是直接路径插入(direct-path insert),不走 Buffer Cache、跳过大部分 Undo,但硬性前提没满足时,Oracle 会直接放弃该 hint:
- 表上有启用的触发器——临时禁用:
ALTER TABLE t DISABLE ALL TRIGGERS,完事后记得ENABLE - 当前事务中已对该表执行过常规
INSERT/UPDATE/DELETE——/*+ APPEND_VALUES */必须是该事务中对该表的**第一条 DML** - 表是索引组织表(IOT)或被其他表的外键引用——这两种情况不支持直接路径插入,
/*+ APPEND_VALUES */会被忽略 - 目标列含
NOT NULL约束但传了NULL字面量——错误在解析阶段就报出,不是 hint 失效,而是语义错误
FORALL 插入时要不要加 COMMIT?
要,而且必须显式写 COMMIT。原因很实在:
- SQL*Plus 默认
AUTOCOMMIT OFF,PL/SQL 块里不COMMIT就等于没插 - 直接路径插入的数据写在高水位线(HWM)之上,不进 Buffer Cache,其他会话即使查也看不到,直到你
COMMIT - 旧版 SQL Developer 可能缓存统计信息,
COUNT(*)返回 0 不代表失败,验证请用:SELECT /*+ FULL(t) */ COUNT(*) FROM t
插几千行还用 /*+ APPEND_VALUES */ 吗?
不推荐。它专为几十到一两百行设计,值必须是字面量(不能是绑定变量),且 VALUES 列表过长会导致硬解析压力飙升,甚至退化为常规插入:
- 插 ≤ 100 行:用
/*+ APPEND_VALUES */,代码干净,性能好 - 插 ≥ 1000 行:改用
INSERT /*+ APPEND */ SELECT ... FROM (VALUES ..., ..., ...)或拆成多个FORALL批次(比如每批 500 行) - 若数据来自查询(如从源表拉),优先走
INSERT /*+ APPEND */ INTO t SELECT ... FROM s,比任何 VALUES 方式都快 - 有唯一索引时,
/*+ APPEND_VALUES */仍可运行,但索引维护拖慢整体速度;更优解是先ALTER INDEX idx_name UNUSABLE,插完再REBUILD
表和索引要不要设 NOLOGGING?
可以设,但得看归档模式和业务容灾要求:
- 查当前状态:
SELECT name, log_mode FROM v$database - 归档模式下,
ALTER TABLE t NOLOGGING+/*+ APPEND */能大幅减少 redo 日志;非归档模式下效果有限 -
NOLOGGING的代价是:一旦出故障,这部分数据无法通过归档日志恢复——只适合可重跑的 ETL 场景 - 索引同样可设
NOLOGGING,但重建时需注意:如果后续要用FORCE LOGGING,那设了也没用
真正卡住性能的往往不是某一个 hint,而是表状态、事务顺序、索引可用性这三者的配合。哪怕只漏掉一条触发器禁用,整个批量插入就退回单行效率。











