繁体   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