JDBC批量插入性能
我需要将几百万条logging插入到MySQL数据库中。 我一次批量插入100万。 请参阅下面的代码。 这似乎很慢。 有没有什么办法来优化它?
try { // Disable auto-commit connection.setAutoCommit(false); // Create a prepared statement String sql = "INSERT INTO mytable (xxx), VALUES(?)"; PreparedStatement pstmt = connection.prepareStatement(sql); Object[] vals=set.toArray(); for (int i=0; i<vals.length; i++) { pstmt.setString(1, vals[i].toString()); pstmt.addBatch(); } // Execute the batch int [] updateCounts = pstmt.executeBatch(); System.out.append("inserted "+updateCounts.length);
我有一个与MySQL类似的性能问题,并通过在连接url中设置useServerPrepStmts和rewriteBatchedStatements属性来解决它。
Connection c = DriverManager.getConnection("jdbc:mysql://host:3306/db?useServerPrepStmts=false&rewriteBatchedStatements=true", "username", "password");
我想扩展Bertil的答案,因为我一直在试验连接URL参数。
rewriteBatchedStatements=true
是重要的参数。 useServerPrepStmts
默认已经是false,甚至将其更改为true在批量插入性能方面没有太大的区别。
现在我认为是时候写rewriteBatchedStatements=true
如何显着提高性能。 这是通过rewriting of prepared statements for INSERT into multi-value inserts when executeBatch()
( Source ) rewriting of prepared statements for INSERT into multi-value inserts when executeBatch()
。 这意味着每次调用executeBatch()
时,不要将以下n
INSERT语句发送到mysql服务器:
INSERT INTO X VALUES (A1,B1,C1) INSERT INTO X VALUES (A2,B2,C2) ... INSERT INTO X VALUES (An,Bn,Cn)
它会发送一个INSERT语句:
INSERT INTO X VALUES (A1,B1,C1),(A2,B2,C2),...,(An,Bn,Cn)
你可以通过切换mysql日志logging(通过SET global general_log = 1
)观察它,这将login到每个语句发送到MySQL服务器的文件。
你可以用一个插入语句来插入多行,每次做几千个就可以大大加快速度,也就是说,而不是像INSERT INTO tbl_name (a,b,c) VALUES(1,2,3);
插入3个INSERT INTO tbl_name (a,b,c) VALUES(1,2,3);
INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(1,2,3),(1,2,3);
(可能是JDBC .addBatch()现在可以做类似的优化 – 尽pipemysql addBatch过去一直未得到优化,只是发出个别查询 – 我不知道最近的驱动程序是否仍然如此)
如果你真的需要速度,使用LOAD DATA INFILE从逗号分隔的文件加载你的数据,我们可以做7-8倍的加速比做数千万的插入。
如果:
- 这是一个新表,或者要插入的数量大于已经插入的数据
- 桌子上有索引
- 在插入过程中,您不需要对表格进行其他访问
然后ALTER TABLE tbl_name DISABLE KEYS
可以大大提高插入的速度。 完成后,运行ALTER TABLE tbl_name ENABLE KEYS
开始构build索引,这可能需要一段时间,但不会像每次插入那样长。
您可以尝试使用DDBulkLoad对象。
// Get a DDBulkLoad object DDBulkLoad bulkLoad = DDBulkLoadFactory.getInstance(connection); bulkLoad.setTableName(“mytable”); bulkLoad.load(“data.csv”);
try { // Disable auto-commit connection.setAutoCommit(false); int maxInsertBatch = 10000; // Create a prepared statement String sql = "INSERT INTO mytable (xxx), VALUES(?)"; PreparedStatement pstmt = connection.prepareStatement(sql); Object[] vals=set.toArray(); int count = 1; for (int i=0; i<vals.length; i++) { pstmt.setString(1, vals[i].toString()); pstmt.addBatch(); if(count%maxInsertBatch == 0){ pstmt.executeBatch(); } count++; } // Execute the batch pstmt.executeBatch(); System.out.append("inserted "+count);