我有一个称为OrderEvent的父实体和一个称为PreCondition的子实体。一个OrderEvent可以具有多个PreConditions(> = 200)。我需要保存100000 OrderEvent + 100000 * 200前提条件。我使用Repository.save(OrderEvents列表)并每1000条记录保存到DB中。插入1000个OrderEvents大约需要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);
}
答案 0 :(得分:2)
这通常取决于数据库设置,例如客户端的等待时间是多少,表上的索引是什么,查询如何锁定表等等。
确保您了解在网络操作上花费了多少时间。这可能是限制因素,尤其是如果您的数据库位于世界的另一端。
首先确定客户端和数据库服务器之间的延迟是多少。如果是10毫秒,则逐行插入此代码将是:100,000 * 200 * 10毫秒= 200000s〜56h。这非常慢,因此请确保将批处理插入与JDBC一起使用。
有时,通过创建影子表可以大大加快插入过程:
OrderEvents
和PreCondition
表相同的新表。某些RDBMS允许使用CREATE TABLE ... AS SELECT ... FROM ...
语法。INSERT INTO ... SELECT ... FROM ...
。不过,最好的选择是跳过JDBC并切换到数据库提供的批量加载实用程序,例如Oracle DB具有External Tables和SQL*Loader。这些工具经过专门设计,可以有效地吸收大量数据,而JDBC是通用接口。
答案 1 :(得分:0)
使用DB服务器的BULK处理操作更好地做到这一点。 是的,这是完全不同的过程,但是将需要几秒钟。甚至没有几分钟。
不幸的是,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
答案 2 :(得分:0)
在c#中,我可以将SqlBulkCopy用于此类任务。
也许在Java中有一个等效的API。 像这样的东西:com.microsoft.sqlserver.jdbc.SQLServerBulkCopy