【问题标题】:Oracle and JDBC performance: INSERT ALL vs preparedStatement.addBatchOracle 和 JDBC 性能:INSERT ALL 与preparedStatement.addBatch
【发布时间】:2011-06-21 13:56:33
【问题描述】:

我有一个带有 Oracle 数据库后端的 Java 应用程序,我需要在其中插入多行。我看过关于 inserting multiple rows into Oracle 的讨论,但我也对混合使用 JDBC 对性能的影响感兴趣。

我看到了一些可能性:

选项 1: 使用单行插入 PreparedStatement 并多次执行:

String insert = "Insert into foo(bar, baz) values (?, ?)";
PreparedStatement stmt = conn.prepareStatement(insert);
for(MyObject obj : someList) {
    stmt.setString(1, obj.getBar());
    stmt.setString(2, obj.getBaz());
    stmt.execute();
}

选项 2: 构建一个 Oracle INSERT ALL 语句:

String insert = "INSERT ALL " +
    "INTO foo(bar, baz), (?, ?) " +
    "INTO foo(bar, baz), (?, ?) " +
    "SELECT * FROM DUAL";
PreparedStatement stmt = conn.prepareStatement(insert);
int i=1;
for(MyObject obj : someList) {
    stmt.setString(i++, obj.getBar());
    stmt.setString(i++, obj.getBaz());
}
stmt.execute();

选项 3: 使用 PreparedStatement 的 addBatch 功能:

String insert = "Insert into foo(bar, baz) values (?, ?)";
PreparedStatement stmt = conn.prepareStatement(insert);
for(MyObject obj : someList) {
    stmt.setString(1, obj.getBar());
    stmt.setString(2, obj.getBaz());
    stmt.addBatch();
}
stmt.execute();

我猜另一种可能性是创建一个 CSV 文件并使用 SQL 加载器,但我不确定如果加上创建 CSV 文件的开销,这是否真的会更快...

那么哪个选项的执行速度最快?

【问题讨论】:

  • 请分享您的测量结果。请注意,Oracle 对批处理大小有限制。如果我没记错的话,一次是1000条记录,所以你需要每1000条记录调用executeBatch()。相关:stackoverflow.com/questions/2467125/…
  • 我已经成功地使用了 2500 的批量大小,但我还没有看到超过 500 大小的实际性能提升
  • 我在 12c 上使用了 1,000,000 的批量大小,并且看到与 1,000 或 10,000 或 100,000 个记录批次大致相同的记录/秒比率。但是,我也强制插入并行。

标签: oracle jdbc performance


【解决方案1】:

PreparedStatementaddBatch() 功能用于1,000,000 行以下的任何内容。

您添加到代码中的每个附加组件都会增加依赖关系和故障点。

如果你走这条路(外部表、sql 加载器等),请确保它真的值得。

将数据序列化为 csv 文件,将其移动到数据库可读的位置将很容易花费一秒钟左右的时间。

在那段时间里,如果我只是吸收它并开始使用 JDBC 插入,我可以插入 20,000 行。

【讨论】:

    【解决方案2】:

    即使没有直接路径加载,SQL Loader 似乎也是更好的方法,但它很难维护。 批量插入比单个插入语句快 2-4 倍。 像批量插入一样插入所有内容,这两者都会比 PL/SQL 实现更快。

    您可能还想阅读this AskTom 主题。

    【讨论】:

    • 就我而言,批量插入比单行插入快 100 倍以上。
    【解决方案3】:

    使用批处理对程序员来说是透明的。这是来自here的引用:

    设置连接批量值

    您可以为 Oracle 连接中的任何 Oracle 准备语句指定默认批处理值。 > 为此,请使用 OracleConnection 对象的 setDefaultExecuteBatch() 方法。例如,以下代码将与 conn 连接对象关联的所有准备好的语句对象的默认批处理值设置为 20:

    ((OracleConnection)conn).setDefaultExecuteBatch(20);

    即使这为连接的所有准备好的语句设置了默认批处理值,您也可以通过在各个 Oracle 准备好的语句上调用 setDefaultBatch() 来覆盖它。

    连接批处理值将应用于设置此批处理值后创建的语句对象。

    【讨论】:

    • 从 12.1 开始,此方法已被弃用,取而代之的是标准 JDBC 批处理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-12
    • 1970-01-01
    • 2017-05-23
    • 1970-01-01
    • 2011-12-20
    • 2018-01-29
    • 2012-08-21
    相关资源
    最近更新 更多