Oracle亿级大表高效插入不存在PLAYER_ID记录的方案
亿级表无索引增量插入高效方案
原NOT IN写法跑7小时未完成属于典型的语法选型+优化器特性没用对的问题:
NOT IN处理大结果集子查询时,Oracle优化器很难生成最优执行计划,且一旦子查询返回的player_id存在NULL值,整个查询会直接返回空结果,逻辑可靠性差。- 常规串行插入走缓冲区缓存,单进程扫描亿级表、逐行匹配的效率极低,完全撑不住1.12亿的数据量。
最高效执行方案
全程不需要创建任何索引,利用Oracle原生的直接路径插入、并行执行、哈希连接特性即可,亿级数据量通常10~30分钟即可跑完,步骤如下:
- 会话级开启并行DML开关,否则后续并行提示不会生效:
ALTER SESSION ENABLE PARALLEL DML;
- 执行插入语句,通过HINT强制走最优执行路径:
INSERT /*+ APPEND PARALLEL(tmp 8) PARALLEL(tot 8) USE_HASH(tmp tot) */ INTO table_total tot SELECT tmp.* FROM table_temp tmp WHERE NOT EXISTS ( SELECT 1 FROM table_total tot_inner WHERE tot_inner.player_id = tmp.player_id );
- 执行完成后立即提交事务,释放锁资源:
COMMIT;
关键HINT作用说明
APPEND:启用直接路径插入,跳过数据库缓冲区缓存、块空闲空间查找、行链接校验等常规插入的冗余流程,直接在表高水位线以上连续写入数据,写入效率比常规插入高3~10倍。PARALLEL:指定8个并行进程同时扫描两张表、执行关联判断、写入数据,充分利用服务器多核CPU与IO带宽,并行度可根据服务器CPU核数调整,建议设置为物理CPU核数的50%~75%,不要占满资源影响其他业务。USE_HASH:强制优化器选择哈希连接做两表匹配,对于千万/亿级无索引大表的关联场景,哈希连接的效率比嵌套循环、排序合并连接高一个数量级。- 用
NOT EXISTS替代NOT IN,既规避了NOT IN对NULL值的逻辑bug,也能让优化器稳定选择哈希反连接执行计划,不会出现执行计划漂移导致的耗时异常。
无并行权限备选方案
如果账号没有并行DML权限,就用哈希取模分批插入,把大事务拆成小事务执行,避免单事务撑爆UNDO表空间,也能比原NOT IN写法快数倍:
-- 按player_id对12取模拆成12批执行,每批约900万数据,每执行完一批提交一次 -- 批次号从0到11依次执行即可 INSERT INTO table_total SELECT tmp.* FROM table_temp tmp WHERE NOT EXISTS (SELECT 1 FROM table_total t WHERE t.player_id = tmp.player_id) AND MOD(tmp.player_id, 12) = 0;
执行注意事项:
- 建议在业务低峰期执行,
APPEND直接路径插入会持有table_total的表级排他锁,执行期间会阻塞其他对该表的读写操作。- 执行前确认UNDO、REDO表空间有足够余量,避免执行中途因表空间不足触发回滚,亿级数据的大事务回滚耗时可能远高于执行耗时。
- 不要随便加多余的HINT,避免干扰优化器的正常判断。
内容的提问来源于stack exchange,提问作者punky
相关产品推荐
相关产品推荐

