问题描述
我要在MysqL表中插入几百万行。我正在使用如下所示的准备好的语句。
创建单个插入字符串(如正下方的字符串)会更快吗?
从Is 22 seconds a good time for inserting 500 rows in mysql?开始的单字符串方法:
INSERT INTO example
(example_id,name,value,other_value)
VALUES
(100,'Name 1','Value 1','Other 1'),(101,'Name 2','Value 2','Other 2'),(102,'Name 3','Value 3','Other 3'),(103,'Name 4','Value 4','Other 4');
我目前正在做什么:
//
// method to do upload
//
public static void doUpload(Connection conn) {
log.info("Deleting existing data...");
Database.update("truncate table attribute",conn);
log.info("Doing inserts");
String sqlString = "insert into attribute values (null,?,?)";
int max = 1000000;
PreparedStatement ps = Database.getPreparedStatement(sqlString,conn);
for (int i = 0; i < max; i++) {
// add params
String subjectId = i+"";
addParam(subjectId,"GENDER",getGender(),ps);
addParam(subjectId,"AGE",getAge(),"CITY",getCity(),"FAVORITE_COLOR",getColor(),"PET",getPet(),ps);
if (i % 1000 == 0) {
log.info("Executing " + i + " of " + max);
Database.execute(ps);
log.info("Done with batch update");
ps = Database.getPreparedStatement(sqlString,conn);
}
}
if (Database.isClosed(ps) == false) {
Database.execute(ps);
}
}
//
// method to add param to the prepared statement
//
private static void addParam(String subjectId,String name,String val,PreparedStatement ps) {
ArrayList<String> params;
params = new ArrayList<String>();
params.add(subjectId + "");
params.add(name);
params.add(val);
Database.addToBatch(params,ps);
}
//
// addToBatch
//
public static void addToBatch(List<String> params,PreparedStatement ps) {
try {
for (int i = 0; i < params.size(); i++) {
ps.setString((i + 1),params.get(i));
}
ps.addBatch();
} catch (Exception exp) {
throw new RuntimeException(exp);
}
}
进行这种插入的最快方法是什么?
我目前大约在5秒钟内插入1000行。期望比这好得多是否合理? 我正在本地运行,并且已经将要插入的表上的所有索引删除。
解决方法
使用JDBC进行批量插入的最快方法是使用addBatch / executeBatch, 您似乎已经在做。
有关示例代码,请参见
但这只会为您带来如此多的性能。
为了真正提高性能,请在您的JDBC URL中添加rewriteBatchedStatements=true
。
您会看到一个明显的进步。
请参见MySQL and JDBC with rewriteBatchedStatements=true
请记住,您在“单字符串方法”中的建议是相似的,但是rewriteBatchedStatements=true
也使与数据库的网络通信更加有效。
不确定Database.getPreparedStatement
在做什么,但是通常不需要在每次执行批处理后重新创建PreparedStatement
对象,仍然可以重用它。
您是否尝试过设置更大的批量大小?截至目前,您的批次大小为1000,您是否尝试过使其更大?
准备好的语句具有安全性的优点。从理论上讲,准备好的语句为precompiled,并且仍应提供更好的性能。