【问题标题】:Spring Boot + Hibernate - Insert query getting slow downSpring Boot + Hibernate - 插入查询变慢
【发布时间】:2021-10-22 08:18:28
【问题描述】:

我正在开发一个 Spring Boot 应用程序。在这里,我有 100,000 条记录通过不同的进程插入到数据库中。并将其一一插入。我不能批量插入。

所以在启动一些任务时表现不错并且没有花费太多时间,但是应用程序进程一些和数据库增长缓慢 - 2,插入时间正在增加。

我怎样才能加快这个过程或避免让它变慢?

【问题讨论】:

  • 您可以尝试将要保存的所有对象添加到列表中,然后调用 saveAll 方法....一般 save 比 saveAll 需要更多时间

标签: spring spring-boot hibernate jpa


【解决方案1】:

插入的最快方法是使用准备好的语句。

注入 jdbcTemplate 并使用它的 batchUpdate 方法并设置批处理大小。速度快如闪电。

如果你认为你不能使用批量插入,这对我来说很难理解,那么将批量大小设置为 1。

然而,最优化的批量大小肯定比这要大,并且取决于插入语句。你必须尝试一下。

这里有一个名为 LogEntry 的类的示例。用您的类、表、列和属性替换类、表、列和属性,并将其放入您的存储库实现中。

还请确保您设置了此处提到的应用程序属性https://stackoverflow.com/a/62414315/12918872

关于 id 生成器,可以设置一个序列 id 生成器(也显示在该链接中),或者在我的情况下,只需通过在开始时询问表的 maxId 然后向上计数来自行生成它。

  @Autowired
  private JdbcTemplate jdbcTemplate;

   public void saveAllPreparedStatement2(List<LogEntry> logEntries) {
    int batchSize = 2000;
    int loops = logEntries.size() / batchSize;
    for (int j = 0; j <= loops; j++) {
      final int x = j;
      jdbcTemplate.batchUpdate("INSERT INTO public.logentries(\r\n"
          + "    id, col1, col2, col3, col4, col5, col6)\r\n"
          + "    VALUES (?, ?, ?, ?, ?, ?, ?);\r\n", new BatchPreparedStatementSetter() {
            public void setValues(PreparedStatement ps, int i) throws SQLException {
              int counter = x * batchSize + i;
              if (counter < logEntries.size()) {
                LogEntry logEntry = logEntries.get(counter);
                ps.setLong(1, (long) logEntry.getId());
                ps.setString(2, (String) logEntry.getAttr1());
                ps.setInt(3, (int) logEntry.getAttr2());
                ps.setObject(4, logEntry.getAttr3(), Types.INTEGER);
                ps.setLong(5, (long) logEntry.getAttr4());
                ps.setString(6, (String) logEntry.getAttr5());
                ps.setObject(7, logEntry.getAttr6(), Types.VARCHAR);
              }
            }

            public int getBatchSize() {
              if (x * batchSize == (logEntries.size() / batchSize) * batchSize) {
                return logEntries.size() - (x * batchSize);
              }
              return batchSize;
            }
          });
    }
  }

【讨论】:

    【解决方案2】:

    给你一些建议:

    1. 如果您说插入更多记录,则插入时间越来越长,这是不正常的。根据我的经验,很可能是由于程序中的一些逻辑错误导致您在插入更多记录时处理了更多必要的数据。所以请先修改你的插入逻辑。

    2. 如果实体使用IDENTITY 生成是 ID,Hibernate 无法批量插入实体。您必须将其更改为使用SEQUENCE 以使用pooledpooled-lo 算法生成ID。

    3. 确保在休眠配置中启用 JDBC 批处理功能

    4. 如果您使用的是 PostgreSQL,您可以在 JDBC 连接字符串中添加 reWriteBatchedInserts=true,这将提供 2-3 倍的性能提升。

    5. 确保每个事务将插入一批实体然后提交,但不是每个事务只插入一个实体。

    关于第(2)、(3)、(4)点的更多细节,可以参考我之前在this的回答。

    【讨论】:

      猜你喜欢
      • 2018-05-15
      • 2017-11-20
      • 2022-01-06
      • 1970-01-01
      • 2018-11-30
      • 2017-08-03
      • 2018-10-02
      • 2018-01-21
      • 2014-09-10
      相关资源
      最近更新 更多