用Java快速将数据导入mysql
Posted
技术标签:
【中文标题】用Java快速将数据导入mysql【英文标题】:Fast import data to mysql in Java 【发布时间】:2016-04-21 23:36:11 【问题描述】:通过 Java 代码将大约 500.000 条记录从 CSV 文件插入 mysql 数据库需要多长时间?托管在本地主机上的数据库。
表结构:AI id, | varchar(8) | datetime | int | varchar(2)
。我的代码需要在 40 分钟内插入 70.000 条记录。有什么方法可以更快地做到这一点吗?
这是我的代码的主要部分:
CsvReader pro
ducts = new CsvReader(path);
products.readHeaders();
stmt = con.createStatement();
String updateString = "INSERT INTO table (T_V1, date, T_V2, T_V3) VALUES (?,?,?,?)";
PreparedStatement preparedStatement = con.prepareStatement(updateString);
while (products.readRecord())
v1= products.get("V1");
date = format.parse(products.get("Date") + " " + products.get("Hour"));
java.sql.Date dateDB = new java.sql.Date(data.getTime());
v2 = products.get("V2");
v3 = products.get("V3");
preparedStatement.setString(1, v1);
preparedStatement.setDate(2,dateDB);
preparedStatement.setInt(3, Integer.parseInt(v2));
preparedStatement.setString(4, v3);
preparedStatement.executeUpdate();
根据您的建议,我将语句的创建移出循环。在我有 29 rps 之后,现在我每秒有 33 条记录。
【问题讨论】:
将语句的创建移出while循环 你不应该使用Java导入数据,使用mysqlimport实用程序。 曾经我不得不将基于pcap
文件的数百万条记录插入数据库。将数据分成块并使用线程运行它要快得多。不知道它在 MySQL 中是如何工作的。我使用 Oracle DB,并让生产者线程创建表类型(代表一组数据库记录),让消费者线程创建数据库事务并使用这些表类型参数调用存储过程,将数据插入数据库。但一般来说,如果你已经有 CSV 文件,最快的方法是使用一些 SQL Loader 替代品dev.mysql.com/doc/refman/5.1/en/load-data.html
按照建议,在循环外仅创建一次 PreparedStatement
,此外,请考虑按照 this post 中的建议使用批量插入 (preparedStatement.addBatch()
)。
我将语句的创建移出循环。不幸的是,我不得不用 Java 来做这件事
【参考方案1】:
如果不需要使用Java插入代码,可以使用SQL插入数据。
在您的 GUI 工具(SQLyog 等)中使用以下代码:
LOAD DATA LOCAL INFILE 'D:\\Book1.csv' INTO TABLE table_name FIELDS TERMINATED BY ','
ENCLOSED BY '"' LINES TERMINATED BY '\r\n' (column_name1, column_name2);
【讨论】:
【参考方案2】:我可能会选择使用 MySQL 中的 LOAD DATA
语句而不是使用 Java:
LOAD DATA LOCAL INFILE '/path/to/your/file.csv' INTO TABLE table;
这将避免您当前的大量开销,假设您在将每一行插入 MySQL 之前对其进行处理。
您可以使用原始 JDBC 从 Java 执行 LOAD DATA
语句。
【讨论】:
但是 OP 明确要求通过 Java 传递。 如果 OP 对此使用 Java 的预感是错误的,这将毫无意义。LOAD DATA
是加载大量数据的首选工具,如果可以的话。
OP 在 cmets 中确认该解决方案需要使用 Java。
当然,我没想到可以这样!但它只有在我不必更改文件结构的任何内容时才有用,对吧?
是的。如果您需要对原始数据进行按摩,那么使用 Java 可能是最好的选择。【参考方案3】:
你应该去批量插入
PreparedStatement prepStmt = con.prepareStatement("Insert query");
prepStmt.setString(1,parameter1);
prepStmt.addBatch();
// for next set of parameter
prepStmt.setString(1,parameter2);
prepStmt.addBatch();
int [] numUpdates=prepStmt.executeBatch()
)
见Which is faster: multiple single INSERTs or one multiple-row INSERT?
How to do a batch insert in MySQL
【讨论】:
【参考方案4】:不要在while
内部创建PreparedStatement
,而是在外部创建PreparedStatement
并简单地在while
循环内设置值。
类似
String updateString = "INSERT INTO table (T_V1, date, T_V2, T_V3) VALUES (?,?,?,?)";
PreparedStatement preparedStatement = con.prepareStatement(updateString);
while (products.readRecord())
v1= products.get("V1");
date = format.parse(products.get("Date") + " " + products.get("Hour"));
java.sql.Date dateDB = new java.sql.Date(data.getTime());
v2 = products.get("V2");
v3 = products.get("V3");
preparedStatement.setString(1, v1);
preparedStatement.setDate(2,dateDB);
preparedStatement.setInt(3, Integer.parseInt(v2));
preparedStatement.setString(4, v3);
preparedStatement.executeUpdate();
此外,您应该提交数据库引擎内存可以处理的每一行,否则在一定数量的插入后系统会非常慢。
请注意,通常应该可以在 40 分钟内创建超过 70.000 条记录。可能您的网络存在瓶颈。它是 java 应用程序的本地数据库还是远程服务器?如果是远程服务器,请检查连接速度。
【讨论】:
本地数据库【参考方案5】:首先,您可以在循环之外创建准备好的语句。您还可以重构代码以使用多线程,因为您的插入语句似乎不相互依赖,因此您可以通过并行拆分来处理所有数据。
但是对于您的问题“多久...”没有绝对的答案。 这取决于托管 mysql 的机器和执行 java 代码的机器:核心数、可用内存等。
【讨论】:
我把它移出了循环。我知道没有答案,但我认为有可能做得更快,所以我做错了。多线程对我来说可能太高了:) 但是,谢谢你的回复以上是关于用Java快速将数据导入mysql的主要内容,如果未能解决你的问题,请参考以下文章