Mysql JDBC批插入性能
我需要在mysql数据库中插入数亿条记录。我一次批量插入一百万个。请看下面我的代码。看起来很慢。有没有办法优化它Mysql JDBC批插入性能,mysql,performance,jdbc,batch-file,Mysql,Performance,Jdbc,Batch File,我需要在mysql数据库中插入数亿条记录。我一次批量插入一百万个。请看下面我的代码。看起来很慢。有没有办法优化它 try { // Disable auto-commit connection.setAutoCommit(false); // Create a prepared statement String sql = "INSERT INTO mytable (xxx), VALUES(?)"; Prepar
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);
试试看{
//禁用自动提交
connection.setAutoCommit(false);
//创建准备好的语句
字符串sql=“插入mytable(xxx),值(?”;
PreparedStatement pstmt=connection.prepareStatement(sql);
Object[]vals=set.toArray();
对于(int i=0;i您可以用一条insert语句插入多行,一次执行几千行可以大大加快速度,也就是说,不必执行例如3次形式的插入,例如插入tbl_名称(a,b,c)值(1,2,3);
,您可以插入tbl_名称(a,b,c)值(1,2,3),(1,2,3);(可能是JDBC.addBatch()现在也做了类似的优化——尽管mysql addBatch过去完全没有优化,只是发出了单独的查询——我不知道最近的驱动程序是否仍然如此)
如果您确实需要速度,请使用从逗号分隔的文件加载数据,这样做的速度是执行数千万次插入的速度的7-8倍。如果:
然后,
ALTER TABLE tbl\U name DISABLE KEYS
可以极大地提高插入的速度。完成后,运行ALTER TABLE tbl\U name ENABLE KEYS
开始构建索引,这可能需要一段时间,但比每次插入都要长。您可以尝试使用DDBulkLoad对象
// Get a DDBulkLoad object
DDBulkLoad bulkLoad = DDBulkLoadFactory.getInstance(connection);
bulkLoad.setTableName(“mytable”);
bulkLoad.load(“data.csv”);
我在mysql中遇到了类似的性能问题,通过在连接url中设置UseServerPrepsmts和rewriteBatchedStatements属性解决了这个问题
Connection c = DriverManager.getConnection("jdbc:mysql://host:3306/db?useServerPrepStmts=false&rewriteBatchedStatements=true", "username", "password");
我想进一步介绍Bertil的答案,因为我一直在试验连接URL参数
rewriteBatchedStatements=true
是一个重要参数。UseServerPrepsMTS
在默认情况下已为false,即使将其更改为true,也不会对批插入性能产生太大影响
现在我想是时候写一写rewriteBatchedStatements=true
是如何显著提高性能的了。它通过重写准备好的语句,以便在executeBatch()时插入到多值插入中(
)。这意味着每次调用executeBatch()
时,都不会向mysql服务器发送以下n
INSERT语句:
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\u log=1
)来观察它,该日志会将发送到mysql服务器的每条语句记录到一个文件中。试试看{
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);
//禁用自动提交
connection.setAutoCommit(false);
int maxInsertBatch=10000;
//创建准备好的语句
字符串sql=“插入mytable(xxx),值(?”;
PreparedStatement pstmt=connection.prepareStatement(sql);
Object[]vals=set.toArray();
整数计数=1;
对于(int i=0;i)顺便说一句,您的代码有点损坏(并且过早地被截断),您使用的是哪种驱动程序?普通JDBC还是JDBC Mysql连接器?我使用的是com.Mysql.JDBC.DriverHow它需要多长时间?您得出的结论是速度慢的比较材料是什么?我只是在本地pc(4gb ram)中插入了100万个测试,花了大约10分钟,只是想知道是否有改进的余地加载数据填充可能是一个不错的选择,但我的输入文件需要清理,我只对插入第二个标记与字符串匹配的特定行感兴趣(空格分隔的标记),加载数据填充足够灵活,可以过滤行吗?我不认为它可以过滤,但你可以自己清理数据,用清理后的数据编写一个新文件,然后加载该文件。我的插入速度现在快了10倍!@Kimble-那么为什么不接受这个答案呢?谢谢,伙计!这就像魔术一样!10秒而不是1小时。当之无愧的+1!有moved.在使用Java驱动程序时,我注意到插入批处理的另一个要求(至少在驱动程序的5.1.10版本中):在SQL语句中,“值”part后面必须跟一个空格,而不是直接用左括号,否则驱动程序将返回到顺序插入。您能解释一下为什么添加useServerPrepStmts=false会起作用吗?阅读后,我会认为它会起相反的作用。我肯定您是对的,我只是不完全理解设置为什么/如何提高性能?谢谢你。@Vipin我不知道。Eran-关于更新,rewriteBatchedStatements=true是否与insert一样提高了更新的性能,因为更新时的语法与insert时的语法不同,并且它不能作为一个整体执行(据我所知)。之所以这样说,是因为我希望在插入时10k+行可能不到1秒,而在更新时100行可能不到1秒。与其进行向下投票,还可以对此进行评论,为什么它可以或不能在中间执行多个批处理而不是一次执行所有批处理时提高性能…看起来上面的答案有一个几乎相同的代码段,即有一个问题。