我需要使用iBatis在单个表(SQL Server 2005)中插入20,000行。最快的方法是什么?我已经在使用批处理模式,但它没有多大帮助:
try {
sqlMap.startTransaction();
sqlMap.startBatch();
// ... execute statements in between
sqlMap.commitTransaction();
} finally {
sqlMap.endTransaction();
}
答案 0 :(得分:4)
除非其他人指的是批量加载器,让我们考虑如何通过SQL做到最好。 (如果您将混合数据发送到不同的表,则批量加载器不能正常工作。)
首先,你不应该使用你正在使用的任何抽象层,在这种情况下是iBatis,因为它实际上会为你提供很少的价值,但是抽象层将有一些(不一定是很多,但有些)CPU成本。您应该只使用原始数据库连接。
接下来,您将发送一堆INSERT语句。问题是你是否应该使用一个简单的字符串作为参数(即INSERT INTO TABLE1 VALUES('x','y',12))vs一个预备语句(INSERT INTO TABLE1 VALUES(?,?,?))。
这取决于您的数据库和数据库驱动程序。
使用简单字符串的问题基本上是内部格式(假设您正在插入Java数据)到字符串的转换成本。将数字或日期转换为String实际上是一个相当昂贵的CPU操作。一些数据库和驱动程序将直接使用二进制数据,而不仅仅是字符串数据。因此,在这种情况下,PreparedStatement可以节省一些CPU节省,而不必转换数据。
缺点是这个因素会因数据库供应商而有所不同,甚至可能是JDBC供应商。例如,Postgres(我相信)只适用于SQL字符串,而不是二进制文件,因此使用PreparedStatement是一种浪费,而不仅仅是自己构建字符串。
接下来,一旦有了语句类型,就要使用JDBC Statement类的addBatch()方法。 addBatch的作用是将SQL语句组合成一个批处理。好处是,您可以发送一个LARGE请求,而不是向DB发送多个请求。这样可以减少网络流量,并且可以显着提高吞吐量。
细节是并非所有驱动程序/数据库都支持addBatch(至少不是很好),但批量的大小也是有限的。您很可能无法为所有20,000行添加addBatch并期望它能够正常工作,尽管这将是最好的选择。此限制也可能因数据库而异。
对于Oracle,在过去,我使用了64K的缓冲区。基本上我写了一个包装函数,它将采用文字INSERT语句,并以64K批次累积它们。
因此,如果您希望通过JDBC批量插入数据,那么这就是实现它的方法。最大的改进是Batch模式,Statement vs PreparedStatement更可能节省一些CPU,如果您的驱动程序支持二进制协议,则可能是网络流量。
测试,冲洗并重复,直到你足够快乐。
答案 1 :(得分:2)
虽然这不是特定于您的数据库服务器,但我之前已成功将行写入csv格式的本地文件,然后让数据库导入该文件。这比插入语句甚至批量插入快得多。
答案 2 :(得分:2)
在SQL Server中,批量插入记录的禁用方法是使用BULK INSERT。但是,此方法从文本文件而不是直接从应用程序加载记录。
创建文件所花费的时间也不会占用帐户。如果能够抵消实际刀片的任何速度增益,您可能需要进行称重。请记住,即使整体速度稍慢,您最终也会占用数据库服务器的时间更短。
您可能尝试的另一件事是将批处理插入(暂存)到完全不同的表中(没有索引或任何内容)。然后将记录从该临时表移动到目标表并删除登台表。这将首先将数据移动到服务器,以便最终插入可以全部发生在sql server本身。但同样:这是一个两步的过程,所以你必须计算两个步骤的时间。
答案 3 :(得分:1)
批量插入最好使用数据库自己的批量加载工具完成。例如,对于Oracle,它是SQL * Loader。通常这些比你能写的任何东西都快。