簡體   English   中英

如何以超快的速度插入 100,000 個父行,每行 200 個子行?

[英]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 批量插入。

有時,通過創建影子表可以顯着加快插入過程:

  1. 創建與OrderEventsPreCondition表相同的新表。 一些 RDBMS 允許CREATE TABLE ... AS SELECT ... FROM ...語法。
  2. 禁用影子表上的外鍵和索引。
  3. 批量插入所有數據。
  4. 在影子表上啟用外鍵和索引。 這有望確保導入的數據是正確的。
  5. 從影子表插入到實際表中,例如通過運行INSERT INTO ... SELECT ... FROM ...
  6. 刪除影子表。

然而,最好的選擇是跳過 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM