/*+ APPEND */ 能提速但需满足条件:表无触发器、非IOT、无外键引用、当前事务未混用DML;否则静默退化或报ORA-12838。
/*+ append */ 能显著提速,但不是加了就生效——它本质是触发直接路径插入(direct-path insert),而这个机制有硬性前提,不满足时要么静默退化为常规插入,要么直接报错 ora-12838。
为什么加了 /*+ APPEND */ 还没快?常见失败条件
直接路径插入绕过 Buffer Cache、跳过 Undo 生成(除非 force logging)、写入 HWM 之上,但前提是表状态和会话环境必须干净:
- 表上不能有启用的触发器——临时禁用用
ALTER TABLE t DISABLE ALL TRIGGERS,完事后记得ENABLE - 不能是索引组织表(IOT)
- 不能被外键约束引用(即其他表的 FK 指向该表)
- 当前事务中已对该表执行过常规 INSERT/UPDATE/DELETE —— 一旦混用,后续
/*+ APPEND */就会报ORA-12838 - 如果表有唯一索引,
/*+ APPEND */仍可运行,但索引维护会拖慢整体速度;此时更推荐先ALTER INDEX idx_name UNUSABLE,插入完再REBUILD
APPEND_VALUES 适合 PL/SQL 批量插几十到几百行
在 PL/SQL 中用 FORALL 插入数组数据时,/*+ APPEND_VALUES */ 是比纯 /*+ APPEND */ 更匹配的选择。它专为 VALUES 场景设计,但有严格限制:
- 不支持绑定变量——所有值必须是字面量,比如
VALUES (1, 'abc'),不能写成VALUES (:a, :b) - VALUES 列表不宜过长:插上千行拼成一个超长 VALUES 列表,SQL 硬解析压力剧增,性能反而不如分批
FORALL+/*+ APPEND_VALUES */ - 插入后数据对其他会话不可见,直到显式
COMMIT;且旧版 SQL Developer 可能因缓存统计信息显示COUNT(*) = 0,验证要用SELECT /*+ FULL(t) */ COUNT(*) FROM t
PL/SQL 中真正高效的组合:FORALL + APPEND_VALUES + 手动 COMMIT
批量插入不是靠单个 hint 堆出来的,而是结构+hint+事务控制协同的结果。下面这段是实测 3000 万行迁移中跑出 7 分钟的关键写法:
DECLARE
TYPE id_array IS TABLE OF users.user_id%TYPE;
TYPE name_array IS TABLE OF users.user_name%TYPE;
v_ids id_array := id_array();
v_names name_array := name_array();
BEGIN
SELECT user_id, user_name BULK COLLECT INTO v_ids, v_names
FROM legacy_users;
<p>FORALL i IN 1..v_ids.COUNT
INSERT /<em>+ APPEND_VALUES </em>/ INTO new_users VALUES (v_ids(i), v_names(i));</p><p>COMMIT; -- 必须显式,SQL*Plus 默认 AUTOCOMMIT OFF
END;注意:FORALL 本身不开启并行,如需进一步提速,可在会话级启用并行 DML:ALTER SESSION ENABLE PARALLEL DML,再配合 /*+ PARALLEL(new_users, 4) */;但并行也受表是否 NOLOGGING、磁盘 I/O 能力制约。
别忽略 nologging 和高水位线的副作用
/*+ APPEND */ 在 NOLOGGING 表上才能发挥最大日志削减效果,但风险同步放大:归档模式下,若此时发生介质故障,这部分数据无法通过重做日志恢复。
- 执行前确认表属性:
SELECT logging FROM user_tables WHERE table_name = 'NEW_USERS' - 临时改属性:
ALTER TABLE new_users NOLOGGING,插入完建议切回LOGGING - HWM 会被永久推高——即使你删掉所有数据,空间也不会自动回收;后续常规插入仍从高位开始找空块,造成“空表也慢”的假象
最易被忽略的一点:直接路径插入的数据,不会触发任何基于行的审计策略或细粒度审计(FGA),如果业务依赖审计日志,这点必须提前评估。


















