[英]Using flush() method on each 100 rows of 10 000 slows transaction
[英]How to insert 100,000 parent rows each with 200 child rows super fast?
我有一个名为 OrderEvent 的父实体和一个名为 PreCondition 的子实体。 一个 OrderEvent 可以有多个 PreConditions(>=200)。 我需要保存 100000 OrderEvent + 100000 * 200 PreCondition。 我使用 Repository.save(list Of OrderEvents) 并将每 1000 条记录保存到数据库中。 插入 1000 个 OrderEvent 大约需要 30 秒。
保存所有 100000 个 OrderEvent 需要将近一个小时。
有什么办法可以把时间降到2分钟以下?
尝试保存存储库的实体方法
public void parseOrder(String path, String collectionName) throws ParseException {
BufferedReader reader;
Connection conn = (Connection) em.unwrap(java.sql.Connection.class);
System.out.println(conn);
try {
reader = new BufferedReader(new FileReader(
path));
String line = reader.readLine();
String jobNumber = line.substring(0, 7).trim();
String recordType = line.substring(7, 9).trim();
Integer len = line.length();
preId = 0L;
postId = 0L;
eventId = 0L;
OrderEvent orderEvent = this.paraseHeader(line,len,jobNumber,collectionName);
Integer count = 1;
Integer batch = 0;
long startTime = System.nanoTime();
List<OrderEvent> list = new ArrayList<OrderEvent>();
while (line != null) {
line = reader.readLine();
if (line == null) {
continue;
}
jobNumber = line.substring(0, 7).trim();
recordType = line.substring(7, 9).trim();
len = line.length();
if (recordType.equals("0H")) {
count++;
batch++;
if (batch.equals(1000)) {
orderRepository.save(list);
list.clear();
long estimatedTime = System.nanoTime() - startTime;
System.out.println("Processed " + batch + " records in " + estimatedTime / 1_000_000_000. + " second(s).");
batch = 0;
startTime = System.nanoTime();
}
list.add(orderEvent);
//orderRepository.saveAndFlush(orderEvent);
orderEvent = this.paraseHeader(line,len,jobNumber,collectionName);
} else if (recordType.equals("2F")) {
this.paraseFeature(line,len,jobNumber,orderEvent);
}
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private OrderEvent paraseHeader (String line,Integer len,String jobNumber,String collectionName) throws ParseException {
String model = line.substring(9, 16).trim();
String processDate = line.substring(len-11,len-3).trim();
String formattedProcessDate = processDate.substring(0,4) + "-" +
processDate.substring(4,6) +"-" + processDate.substring(6,8) + " 00:00:00";
//eventId++;
OrderEvent orderEvent = new OrderEvent(jobNumber,UUID.randomUUID().toString(),collectionName,
formatter.parse(formattedProcessDate));
// preId++;
//postId++;
orderEvent.fillPrecondition("Model", "Stimulus", "OP_EQ", model);
orderEvent.fillPostcondition("Add_Fact","Coded","Response","True");
return orderEvent;
}
private void paraseFeature (String line,Integer len, String jobNumber, OrderEvent orderEvent) {
// preId++;
String feature = line.substring(len-7,len).trim();
orderEvent.fillPrecondition("Feature", "Stimulus", "OP_EQ", feature);
}
这通常取决于数据库设置,例如客户端的延迟是多少,表上的索引是什么,查询如何锁定表等等。
确保您了解在网络操作上花费了多少时间。 这可能是限制因素,特别是如果您的数据库位于世界的另一端。
首先确定客户端和数据库服务器之间的延迟是多少。 如果是 10 毫秒,那么逐行插入将是:100,000 * 200 * 10ms = 200000s ~ 56h。 这非常慢,因此请确保您使用 JDBC 批量插入。
有时,通过创建影子表可以显着加快插入过程:
OrderEvents
和PreCondition
表相同的新表。 一些 RDBMS 允许CREATE TABLE ... AS SELECT ... FROM ...
语法。INSERT INTO ... SELECT ... FROM ...
。然而,最好的选择是跳过 JDBC 并切换到您的数据库提供的批量加载实用程序,例如 Oracle DB 具有外部表和SQL*Loader 。 这些工具专门设计用于有效地摄取大量数据,而 JDBC 是一个通用接口。
在 C# 中,我可以将SqlBulkCopy用于此类任务。
也许在 java 中有一个等效的 API .. 像这样的东西: com.microsoft.sqlserver.jdbc.SQLServerBulkCopy
使用数据库服务器批量处理操作更好地做类似的事情。 是的,这是完全不同的过程,但需要几秒钟。 甚至没有分钟。
不幸的是 HOWTO 非常依赖于 SQL-Server
MS SQL:批量插入: https ://docs.microsoft.com/en-us/sql/t-sql/statements/bulk-insert-transact-sql?view = sql-server-2017
PostgreSQL:复制: https : //www.postgresql.org/docs/current/sql-copy.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.