Oracle 21c批量INSERT性能瓶颈主要在JDBC驱动、事务控制和内存分配:必须用ojdbc8/11、setAutoCommit(false)、单批1000–5000行,否则addBatch退化为N次单条插入。

Oracle 21c 的批量 INSERT 性能瓶颈,90% 不在 SQL 写法本身,而在 JDBC 驱动、事务控制和 Oracle 内部内存分配三处。直接上结论:用错 ojdbc6.jar、漏关 autoCommit、单批超 5000 行,这三件事做错任何一件,addBatch/executeBatch 就退化成 N 次单条插入。
ojdbc8 或 ojdbc11 是硬性前提,别信“universal”包
Oracle 21c 的 Server-Side Batch 优化只在 ojdbc8.jar(JDK 8+)或 ojdbc11.jar(JDK 11+)中实现。旧版 ojdbc6.jar 无论怎么调 addBatch,都只是客户端模拟——每条语句仍单独发包,根本没走批量协议。
- 验证方式:
System.out.println(oracle.jdbc.driver.OracleDriver.getMajorVersion())输出必须是8或11 - Maven 中标 “universal” 的 ojdbc6 包,大概率是重命名的旧包,功能没升级
- Spring Boot 3.3 + JDK 17 环境下,Maven 坐标应为
com.oracle.database.jdbc:ojdbc11
setAutoCommit(false) 是生死线,不是可选项
只要 connection.setAutoCommit(true)(默认值),executeBatch() 就等价于循环执行 N 条 INSERT + N 次 COMMIT。连接池可能在你 close 连接时自动 commit,你以为成功了,其实全是单条提交。
- 必须在
prepareStatement之前调用connection.setAutoCommit(false) -
executeBatch()后必须显式connection.commit(),不能依赖连接关闭或连接池回收 - 异常时要
connection.rollback(),否则事务卡住,后续操作可能被阻塞
单批 size 控制在 1000~5000 行,且需结合数据体积动态调整
Oracle PGA 内存有限,单批太大触发 ORA-04030;太小又浪费网络往返。这个区间不是固定值,取决于单行字段数量和类型:
- 纯 VARCHAR2 字段、每行
- 含 CLOB/BLOB 或字段 > 20 个:降到 1000~2000 行
- 超过 5000 行后性能非线性下降,某些场景下 6500 行就开始丢数据(不是总数据量,是单批)
- 加一句
statement.setFetchSize(0),避免驱动额外拉取元数据,对 insert 场景有效
INSERT ALL 比 VALUES 多次拼接更高效,但有硬限制
当单条记录字段数 > 10 个时,传统 INSERT INTO t(a,b,c) VALUES(?,?,?) 拼 1000 条,Oracle 解析 SQL 的 CPU 开销会反超网络传输。换成 INSERT ALL 可显著降低硬解析次数。
- 写法示例:
INSERT ALL INTO t(a,b) VALUES(?,?) INTO t(a,b) VALUES(?,?) SELECT * FROM DUAL - Oracle 单条
INSERT ALL最多支持约 1000 个INTO子句,超了必须拆批 - 不能用于有触发器或 IDENTITY 列的表——它绕过部分约束校验逻辑
-
executeBatch()返回的是int[],其中Statement.EXECUTE_FAILED表示该位置失败,不会抛异常;必须遍历检查,不能只看是否 throw Exception
最容易被忽略的点是:Oracle 批量执行默认是 all-or-nothing,但 JDBC 层不主动报错,只返回数组。你漏掉 for (int i = 0; i 这一步,等于把失败当成功处理。



















