[英]OutOfMemoryError while inserting data from large JSON file into MySQL database
[英]MySQL Inserting large data sets from file with Java
我需要从CSV文件中将大约180万行插入到MySQL数据库中。 (只有一张桌子)
目前使用Java来解析文件并插入每一行。
你可以想象这需要花费几个小时才能运行。 (10)
我之所以没有将它直接从文件传输到数据库中,是因为数据必须在将数据添加到数据库之前进行操作。
这个过程需要由那里的IT经理来运行。 所以我把它设置为一个很好的批处理文件,让它们在将新的csv文件放到正确的位置后运行。 所以,我需要通过将文件放到某个位置并运行批处理文件来很好地完成这项工作。 (Windows环境)
我的问题是,插入这么多数据的最快方法是什么? 大型插入,来自临时解析文件或一次插入一次? 可能还有其他想法吗?
第二个问题是,如何优化我的MySQL安装以允许非常快速的插入。 (还有一点需要大量选择所有数据)
注意:该表最终将被删除,整个过程将在以后再次运行。
一些澄清:目前使用... opencsv.CSVReader解析文件,然后在每一行上插入。 我正在总结一些专栏而忽略其他专栏。
更多说明:本地DB MyISAM表
快速插入提示:
使用此插入语法:
插入表(col1,col2)值(val1,val2),(val3,val4),...
在插入之前删除所有键/索引。
我可能会选择一个很大的数字,比如10k行,然后从CSV加载那么多行,按下数据,然后进行批量更新,然后重复直到你完成了整个csv。 根据数据的按摩/数量,1.8 mil的行不应该花费10个小时,更多的是1-2个小时,具体取决于您的硬件。
编辑:whoops,遗漏了一个相当重要的部分,你的con必须将autocommit设置为false,我复制它的代码是作为GetConnection()方法的一部分。
Connection con = GetConnection();
con.setAutoCommit(false);
try{
PreparedStatement ps = con.prepareStatement("INSERT INTO table(col1, col2) VALUES(?, ?)");
try{
for(Data d : massagedData){
ps.setString(1, d.whatever());
ps.setString(2, d.whatever2());
ps.addBatch();
}
ps.executeBatch();
}finally{
ps.close();
}
}finally{
con.close();
}
您是否绝对禁止在JDBC驱动程序中禁用自动提交?
这是JDBC客户端的典型性能杀手。
你真的应该在MySQL控制台上使用LOAD DATA来实现这一点,而不是通过代码...
LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;
如果你需要操作数据,我仍然建议在内存中操作,重写为平面文件,并使用LOAD DATA将其推送到数据库,我认为它应该更有效。
另一个想法是:您是否使用PreparedStatement通过JDBC插入数据?
根据您在插入数据之前需要对数据做些什么,您在速度方面的最佳选择是:
您最大的性能问题很可能不是java而是mysql,特别是您插入的表上的任何索引,约束和外键。 在开始插入之前,请确保禁用它们。 在最后重新启用它们将花费相当多的时间,但它比在每个语句之后让数据库评估它们更有效。
由于事务的大小,您可能还会看到mysql性能问题。 您的事务日志将随着许多插入而变得非常大,因此在X次插入(例如10,000-100,000)之后执行提交也将有助于插入速度。
从jdbc层,确保在PreparedStatement而不是普通的executeUpdate()上使用addBatch()和executeBatch()命令。
您可以通过其Connector J JDBC驱动程序中的批处理功能来提高MySQL / Java的批量INSERT性能。
MySQL没有“正确”处理批处理(参见我的文章链接,底部),但它可以重写INSERT以利用奇怪的MySQL语法,例如,您可以告诉驱动程序重写两个INSERT:
INSERT INTO (val1, val2) VALUES ('val1', 'val2');
INSERT INTO (val1, val2) VALUES ('val3', 'val4');
作为单一声明:
INSERT INTO (val1, val2) VALUES ('val1', 'val2'), ('val3','val4');
(请注意,我并不是说你需要以这种方式重写SQL; 驱动程序可以这样做)
我们这样做是为了我们自己的批量插入调查:它产生了一个数量级的差异。 与其他人提到的显式交易一起使用,您将看到总体上有很大改进。
相关的驱动程序属性设置为:
jdbc:mysql:///<dbname>?rewriteBatchedStatements=true
如果你使用LOAD DATA INFILE而不是插入每一行,会不会更快?
我会跑三个线程......
1)读取输入文件并将每一行推入转换队列2)从队列中弹出,转换数据,并推入db队列3)从db队列弹出并插入数据
通过这种方式,您可以在db线程等待其IO完成时从磁盘读取数据,反之亦然
如果你还没有,请尝试使用MyISAM表类型,只需确保在你做之前阅读它的缺点。 它通常比其他类型的表更快。
如果您的表具有索引,则删除它们通常会更快,然后在导入后将其添加回来。
如果您的数据都是字符串,但更适合作为关系数据库,那么最好插入指示其他值的整数而不是存储长字符串。
但总的来说,是的向数据库添加数据需要时间。
这是一个有趣的读物: http : //dev.mysql.com/doc/refman/5.1/en/insert-speed.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.