4

我需要使用 iBatis 在单个表 (SQL Server 2005) 中插入 20,000 行。最快的方法是什么?我已经在使用批处理模式,但它并没有太大帮助:

try {
  sqlMap.startTransaction();
  sqlMap.startBatch();
  // ... execute statements in between
  sqlMap.commitTransaction();
} finally {
  sqlMap.endTransaction();
}
4

4 回答 4

4

除了其他人提到的批量加载程序,让我们考虑如何通过 SQL 最好地做到这一点。(如果您将混合数据发送到不同的表,则批量加载程序无法正常工作。)

首先,您不应该使用您正在使用的任何抽象层,在本例中为 iBatis,因为它实际上不会为您提供很少的价值,但该抽象层将有一些(不一定很多,但一些)CPU 成本。您真的应该简单地使用原始数据库连接。

接下来,您将发送一堆 INSERT 语句。问题是您是否应该对语句使用简单的字符串(即 INSERT INTO TABLE1 VALUES('x','y', 12))与准备好的语句(INSERT INTO TABLE1 VALUES(?, ?, ?))。

这将取决于您的数据库和数据库驱动程序。

使用简单字符串的问题基本上是从内部格式(假设您正在插入 Java 数据)到字符串的转换成本。将数字或日期转换为字符串实际上是相当昂贵的 CPU 操作。一些数据库和驱动程序将直接处理二进制数据,而不是简单的字符串数据。因此,在这种情况下,PreparedStatement 可以节省一些 CPU,因为可能不必转换数据。

缺点是这个因素会因 DB 供应商而异,甚至可能因 JDBC 供应商而异。例如,Postgres(我相信)只适用于 SQL 字符串,而不是二进制,所以使用 PreparedStatement 比简单地自己构建字符串是一种浪费。

接下来,一旦你有了你的语句类型,你就想使用 JDBC Statement 类的addBatch () 方法。addBatch 所做的是将 SQL 语句分组到一个批处理中。好处是,您无需向数据库发送多个请求,而是发送一个 LARGE 请求。这减少了网络流量,并将显着提高吞吐量。

细节是不是所有的驱动程序/数据库都支持 addBatch (至少不是很好),而且你的批处理的大小是有限的。您很可能无法为所有 20,000 行添加批处理并期望它能够正常工作,尽管那将是最好的选择。此限制也可能因数据库而异。

对于 Oracle,过去,我使用 64K 的缓冲区。基本上,我编写了一个包装函数,该函数将采用文字 INSERT 语句,并将它们累积成 64K 批次。

因此,如果您想通过 JDBC 通过 SQL 批量插入数据,这些方法就是这样做的。最大的改进是批处理模式,Statement 与 PreparedStatement 更可能节省一些 CPU,如果您的驱动程序支持二进制协议,可能还会节省网络流量。

测试、冲洗并重复,直到您满意为止。

于 2008-11-13T21:51:22.500 回答
2

虽然这不是特定于您的数据库服务器,但我之前已经成功地将行以 csv 格式写入本地文件,然后让数据库导入文件。这比插入语句甚至批量插入要快得多。

于 2008-11-13T21:21:54.510 回答
2

在 SQL Server 中,批量插入记录的最快方法是使用BULK INSERT。但是,此方法从文本文件而不是直接从您的应用程序加载记录。

它也没有考虑创建文件所花费的时间。如果这抵消了实际插入的任何速度增益,您可能需要权衡。请记住,即使这总体上慢一点,您最终会占用更少的数据库服务器时间。

您可能会尝试的唯一另一件事是将批处理插入(暂存)到一个完全不同的表中(没有索引或任何东西)。然后将记录从该临时表移动到您的目标表并删除临时表。这将首先将数据移动到服务器,以便最终插入都可能发生在 sql server 本身。但同样:这是一个两步的过程,所以你必须计算这两个步骤的时间。

于 2008-11-13T21:23:58.780 回答
1

批量插入最好使用数据库自​​己的批量加载工具来完成。例如,对于 Oracle,它是 SQL*Loader。通常这些比你写的任何东西都要快。

于 2008-11-13T21:02:02.570 回答