从JAVA插入SQL Server时,我可以获得"BULK INSERT"般的速度吗?

Wou*_*ter 6 java sql-server performance bulkinsert sql-server-2014

在寻找从JAVA到SQL Server获取数据的最快方法的过程中,我注意到我能想到的最快的JAVA方法,仍然比使用BULK INSERT慢12倍.

我的数据是从JAVA中生成的,而BULK INSERT只支持从文本文件中读取数据,因此除非我将数据输出到临时文本文件,否则不能使用BULK INSERT.反过来,这当然会成为巨大的性能打击.

从JAVA插入时,插入速度约为每秒2500行.即使当我测量时间的该则ExecuteBatch for循环,和之前.因此,"创建"内存中的数据不是瓶颈.

使用BATCH INSERT插入时,插入速度约为每秒30000行.

两个测试都在服务器上完成.所以网络也不是瓶颈.有关为什么BATCH INSERT更快的任何线索?而且,如果在JAVA内可以获得相同的性能?

这只是一个需要加载一次的大数据集.因此可以临时禁用任何类型的日志记录(已经尝试过简单的日志记录),禁用索引(表没有),锁定,等等,...

到目前为止我的测试设置

数据库:

CREATE TABLE TestTable   
   (  Col1 varchar(50)
    , Col2 int);  
Run Code Online (Sandbox Code Playgroud)

JAVA:

// This seems to be essential to get good speeds, otherwise batching is not used.
conn.setAutoCommit(false);

PreparedStatement prepStmt = conn.prepareStatement("INSERT INTO TestTable (Col1, Col2) VALUES (?, ?)");
for (int i = 1; i <= 10000; i++) {
    prepStmt.setString(1,"X");            
    prepStmt.setInt(2,100);
    prepStmt.addBatch();
}
prepStmt.executeBatch();
conn.commit();
Run Code Online (Sandbox Code Playgroud)

BULK INSERT:

// A text file containing "X 100" over and over again... so the same data as generated in JAVA
bulk insert TestTable FROM 'c:\test\test.txt';
Run Code Online (Sandbox Code Playgroud)

Jer*_*ert 5

尽管这BULK INSERT是进行批量插入的最快方法,但是SQL Server通过本机驱动程序和ODBC支持远程(客户端驱动)批量插入操作。从4.2版本起,JDBC驱动程序,这个功能是通过暴露的SQLServerBulkCopy类,它不直接从文件中读取,但确实从支持阅读RowSetResultSet或自定义实现ISQLServerBulkRecord对生成的数据。此功能等效于.NET SqlBulkCopy类,具有大致相同的接口,并且应该是执行基于服务器的批量操作的最快方法BULK INSERT

编辑:OP的示例

在下面,您可以找到一个示例用例,该用例可用于测试SQLServerBulkCSVFileRecord的性能,该方法类似于SQLServerBulkCopy,但它从文本文件中读取内容。在我的测试案例中,test.txt包含一百万行,其中包含“ X tab 100”

CREATE TABLE TestTable (Col1 varchar(50), Col2 int);
Run Code Online (Sandbox Code Playgroud)

该表不应启用任何索引。

在JAVA中

// Make sure to use version 4.2, as SQLServerBulkCSVFileRecord is not included in version 4.1
import com.microsoft.sqlserver.jdbc.*;

long startTime = System.currentTimeMillis();
SQLServerBulkCSVFileRecord fileRecord = null;  

fileRecord = new SQLServerBulkCSVFileRecord("C:\\temp\\test.txt", true);   
fileRecord.addColumnMetadata(1, null, java.sql.Types.NVARCHAR, 50, 0);  
fileRecord.addColumnMetadata(2, null, java.sql.Types.INTEGER, 0, 0);  
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");  
Connection destinationConnection = DriverManager.getConnection("jdbc:sqlserver://Server\\\\Instance:1433", "user", "pass");
SQLServerBulkCopyOptions copyOptions = new SQLServerBulkCopyOptions();  

// Depending on the size of the data being uploaded, and the amount of RAM, an optimum can be found here. Play around with this to improve performance.
copyOptions.setBatchSize(300000); 

// This is crucial to get good performance
copyOptions.setTableLock(true);  

SQLServerBulkCopy bulkCopy =  new SQLServerBulkCopy(destinationConnection);
bulkCopy.setBulkCopyOptions(copyOptions);  
bulkCopy.setDestinationTableName("TestTable");
bulkCopy.writeToServer(fileRecord);

long endTime   = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println(totalTime + "ms");
Run Code Online (Sandbox Code Playgroud)

使用此示例,我能够达到每秒30000行的插入速度。