我需要在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);
答案 0 :(得分:159)
我遇到了与mysql类似的性能问题,并通过在连接URL中设置 useServerPrepStmts 和 rewriteBatchedStatements 属性来解决这个问题。
Connection c = DriverManager.getConnection("jdbc:mysql://host:3306/db?useServerPrepStmts=false&rewriteBatchedStatements=true", "username", "password");
答案 1 :(得分:53)
我想扩展Bertil的答案,因为我一直在试验连接网址参数。
rewriteBatchedStatements=true
是重要参数。默认情况下,useServerPrepStmts
已经为假,即使将其更改为true,在批量插入效果方面也没有太大差异。
现在我想是时候写rewriteBatchedStatements=true
如何显着提高性能。它由rewriting of prepared statements for INSERT into multi-value inserts when executeBatch()
(Source)完成。这意味着每次调用n
时,不要将以下executeBatch()
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日志记录(SET global general_log = 1
)来观察它,这将记录发送到mysql服务器的每个语句的文件。
答案 2 :(得分:11)
您可以使用一个insert语句插入多行,一次执行几千行可以大大加快速度,也就是说,而不是例如3. INSERT INTO tbl_name (a,b,c) VALUES(1,2,3);
形式的3个插入,你做INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(1,2,3),(1,2,3);
(它可能是JDBC .addBatch()现在做类似的优化 - 尽管mysql addBatch曾经是非常优化的,无论如何只发出个别查询 - 我不知道最近的司机是否仍然如此)
如果您确实需要速度,请使用逗号分隔文件LOAD DATA INFILE加载数据,我们可以获得大约7-8倍的速度,而不是数千万次插入。
答案 3 :(得分:4)
如果:
然后ALTER TABLE tbl_name DISABLE KEYS
可以大大提高插入速度。完成后,运行ALTER TABLE tbl_name ENABLE KEYS
开始构建索引,这可能需要一段时间,但不会像为每个插入操作那样长。
答案 4 :(得分:1)
您可以尝试使用DDBulkLoad对象。
// Get a DDBulkLoad object
DDBulkLoad bulkLoad = DDBulkLoadFactory.getInstance(connection);
bulkLoad.setTableName(“mytable”);
bulkLoad.load(“data.csv”);
答案 5 :(得分:1)
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);