【发布时间】:2019-01-06 10:43:13
【问题描述】:
我正在使用 JDBC 的批处理来插入一百万行。我遇到了 Oracle 驱动程序无法按预期工作 - 批量插入需要很长时间才能工作。 我决定用 Wireshark 嗅探应用程序的流量。我看到了什么?
- Oracle JDBC 驱动发送第一个请求 (1)
- 然后它发送数据 (2),大约 2500 行
- oracle 服务器响应一些包 (3)
- 现在所有剩余的数据都将通过一对一的插入发送,不是批处理!
insert into my_table...insert into my_table...
为什么会这样?我该如何解决这个问题?
表格
create table my_table (val number);
代码
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class scratch_1 {
@Test
public void foo() throws SQLException {
String sql = "insert into my_table (val) values (?)";
try (Connection con = getConnection()) {
con.setAutoCommit(false);
try (PreparedStatement ps = con.prepareStatement(sql)) {
for (long i = 0; i < 100_000; i++) {
ps.setBigDecimal(1, BigDecimal.valueOf(i));
ps.addBatch();
}
ps.executeBatch();
ps.clearBatch();
}
con.commit();
}
}
private Connection getConnection() throws SQLException {
String url = "jdbc:oracle:thin:@localhost:1521:orcl";
String user = "my_user";
String password = "my_password";
return java.sql.DriverManager.getConnection(url, user, password);
}
}
Wireshark 代码来说明发生了什么:
环境
$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
Oracle Database 12.2.0.1 JDBC Driver
服务器:Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit
多次运行查询没有帮助 - 结果相同。
250k 行“批次”插入465s
在服务器端v$sql:
SELECT *
FROM
(SELECT REGEXP_SUBSTR (sql_text, 'insert into [^\(]*') sql_text,
sql_id,
TRUNC(
CASE
WHEN SUM (executions) > 0
THEN SUM (rows_processed) / SUM (executions)
END,2) rows_per_execution
FROM v$sql
WHERE parsing_schema_name = 'MY_SCHEMA'
AND sql_text LIKE 'insert into%'
GROUP BY sql_text,
sql_id
)
ORDER BY rows_per_execution ASC;
【问题讨论】:
-
也许您应该尝试以不同的执行次数运行您的示例代码(并比较它们)。您也可以从另一侧调查视图 v$sql - 列执行,rows_processed。
-
感谢您的评论。我更新了描述,我回答你的问题了吗?
-
PS:你对目标表有任何触发器或约束吗?在 OCI api 的情况下,这变得很重要,因为 Oracle 返回一个值向量,并且您必须检查每个表的批量操作是否成功。
-
不,我不知道。非常简单的表,没有约束或触发器