我需要插入一对夫妇数亿记录到MySQL数据库。 在同一时间,我批其插入1个亿。 请在下面看我的代码。 这似乎是缓慢的。 有什么办法优化它?
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");
我想在贝蒂尔的回答扩大,因为我一直在尝试进行连接的URL参数试验。
rewriteBatchedStatements=true
是重要的参数。 useServerPrepStmts
已经是虚假的默认情况下,甚至将其更改为真不作在批量插入性能方面太大的差别。
现在我觉得是写的时候怎么rewriteBatchedStatements=true
提高性能那么厉害。 它通过这样做rewriting of prepared statements for INSERT into multi-value inserts when executeBatch()
源 )。 这意味着不是发送以下n
INSERT语句MySQL服务器每次executeBatch()
被调用:
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服务器的每个语句。
你可以用一个INSERT语句插入多行,一次做几千可以大大加快速度,那是不是做如形式的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()做类似的优化现在 - 尽管MySQL的addBatch使用才能完全未优化,只是发出单个查询无论如何 - 我不知道这是否仍与最新的驱动程序的情况下)
如果你真的需要的速度,用逗号分隔的文件加载数据LOAD DATA INFILE ,我们避开7-8倍的加速这样做,这样做VS数以千万计的刀片。
如果:
- 这是一个新的表,或要插入的量大则已经插入数据
- 有此表的索引
- 你不需要在插入过程中的其他访问表
然后ALTER TABLE tbl_name DISABLE KEYS
可以大大提高你插入的速度。 当你完成后,运行ALTER TABLE tbl_name ENABLE KEYS
开始建立索引,这可能需要一段时间,但几乎没有,只要做它的每一次插入。
您可以尝试使用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);