![](/img/trans.png)
[英]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.