如何实现Oracle中千万级数据快速入库_使用外部表与存储过程配合。

P粉602998670

P粉602998670

2026-07-30

862人浏览

原创

存储过程不适合逐行插入千万级数据,因其单条dml开销大、易锁表、undo爆满;高效方案应为外部表+insert /+ append /组合,由存储过程仅负责调度、清洗与提交。

直接用存储过程循环 insert 千万级数据,基本等于主动卡死数据库——实测 100 万行就可能跑两小时以上,且极易触发锁表、undo 爆满、日志切换风暴。真正能扛住千万级批量入库的组合,是外部表 + 存储过程控制流程,而不是让存储过程去“干体力活”。

为什么不能在存储过程中逐行 INSERT?

Oracle 的 PL/SQL 循环执行 INSERT 本质仍是单条 DML:每条都走解析 → 执行 → 日志写入 → 一致性读检查全流程。即使加了 COMMIT 控制频率,也无法绕过行级锁、索引分裂、约束校验这些开销。

  • 实测对比:50 万行 CSV,用 C# 拼 SQL 插入耗时 47 分钟;改用外部表 + INSERT /*+ APPEND */ 只需 23 秒
  • 存储过程里写 FOR i IN 1..1000000 LOOP INSERT ... END LOOP,不仅慢,还会把 PGA 吃爆(尤其字段多或含 LOB)
  • 若目标表有外键、非空约束、函数索引,每次 INSERT 都要查字典、校验、维护索引结构,性能断崖下跌

外部表定义必须注意的 4 个硬性参数

外部表不是“建完就能用”,漏掉任意一个关键参数,轻则查不到数据,重则整批失败静默退出。

  • REJECT LIMIT UNLIMITED:不加这个,文件里只要有一行格式错(比如多了一个逗号),整个查询就报 ORA-29913,返回 0 行——不是没数据,是全被当“坏行”拒了
  • CHARACTERSET UTF8(或对应源文件编码):源文件是 UTF-8 却没声明,中文全变 ???;Windows ANSI 文件则要用 WE8MSWIN1252
  • DEFAULT DIRECTORY 对应的 OS 目录,必须由 DBA 运行 CREATE DIRECTORY 并授 READ 权限,且 Oracle 进程用户(如 oracle)要有 OS 层读取权限
  • FIELDS TERMINATED BY ',' 中的分隔符必须和实际文件严格一致;若字段含逗号,得改用 OPTIONALLY ENCLOSED BY '"',否则解析必然错位

存储过程只做三件事:调度、清洗、提交

存储过程在这里的角色是“指挥官”,不是“搬运工”。它不碰数据行,只调用外部表完成批量动作。

oracle知识库
oracle知识库

oracle知识库下载

下载
  • 先用 SELECT COUNT(*) FROM ext_table 快速校验文件行数是否符合预期(避免空文件或截断文件误入)
  • 执行 INSERT /*+ APPEND */ INTO target_table SELECT ... FROM ext_table WHERE ... —— 关键是 /*+ APPEND */,它跳过缓冲区直写数据文件,速度提升 10 倍起
  • 导入后立刻 ANALYZE TABLE target_table COMPUTE STATISTICSDBMS_STATS.GATHER_TABLE_STATS,否则后续查询可能走错执行计划
  • 别在过程里写 COMMITAPPEND 是直接路径操作,本身已隐式提交;手动加 COMMIT 不但多余,还可能干扰并行加载

遇到 BADFILE 堆成山怎么办?

外部表报错不直接告诉你哪一行、哪个字段错了,只往 .bad 文件里扔原始行。靠人眼扫效率极低。

  • 建外部表时务必配 BADFILE 'xxx.bad'LOGFILE 'xxx.log',出错后先看 log 文件末尾的 summary,通常会标出前几处典型错误类型(如日期格式不符、数字超长)
  • SELECT * FROM ext_table WHERE ROWNUM 查前 10 行原始数据,肉眼比对字段顺序、空值占位、引号闭合
  • 如果源文件来自 Excel 导出,大概率含不可见字符(如 \r\n 混用、BOM 头),用 od -c all.csv | head 在服务器上查看十六进制码
  • 临时加 PREPROCESSOR 调用 shell 脚本清洗(如 sed 替换非法字符),但要注意 Oracle 用户必须有执行该脚本的权限,且脚本输出必须是标准输入流

最易被忽略的一点:外部表本身不存数据,也不支持索引和约束。所有质量校验、业务逻辑判断,必须在 INSERT INTO target_table SELECT ... 这一步完成——要么用 WHERE 过滤脏数据,要么用 CASE 转换异常值,别指望外部表替你兜底。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

oracle oracle 存储过程

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

2451

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

449

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

614

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3969

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

1345

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

3561

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

3493

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

642

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

526

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

Java 26官方文档
Java 26官方文档

共0课时 | 0人学习

SQL 教程
SQL 教程

共61课时 | 6.1万人学习