0

如何有效地使用 Hibernate 将大量数据暂存到我们的数据库中?处理超过 25K 列、超过 100 列的记录时的性能并不理想。

让我解释:

背景

我正在为一家在世界各地开展业务的大公司工作。我的任务是领导一个团队(至少在后端)创建一个完整的堆栈应用程序,允许不同级别的管理人员执行他们的任务。当前的后端技术栈是 Java、Spring Boot、Hibernate 和 PostgreSQL。管理层希望将 Excel 文件上传到我们的应用程序并让我们的应用程序解析它们,以便我们可以刷新数据库中的数据。

不幸的是,这些文件的记录范围从 25K 到 50K。我们知道这些 Excel 文件是使用 Excel 中的 SQL 查询生成的。但是,我们不允许使用这些数据直接访问数据库。安全性非常严格,不允许我们访问任何 API、DB 调用等来处理 Excel。由于内存限制和可伸缩性问题,我们使用 SAX 解析来保持低占用空间。解析 Excel 文件后,我们将它们映射到表示临时表的 Hibernate 实体。然后我们将数据从它迁移到我们的其他表。

目前暂存 25K 条记录并将所有数据迁移到我们的其他表需要 15 分钟,这在管理层看来是不可接受的。特别是,因为这需要每天进行。

我尝试过的事情

  • 按照 Vlad在此处的回答在 Hibernate 中启用批处理。这可能使总分期时间缩短了 20 秒。
  • 重写标准和其他查询以获取数据。
  • 减少要处理的数据量(大多数字段都是必需的,因此不能大幅减少数据量)。
  • 为暂存表和目标表中的重要列建立索引。我将索引作为模式生成的一部分。
  • 优化清除已解析数据的缺陷的部分代码。

由于保密协议,我无法发布代码

约束摘要

  • 这个应用程序需要强大的支持来生成相关数据的报告(这是我们使用 RDBMS 的原因之一。此外,数据非常适合关系模型)。
  • 必须维护所有记录的完整审计历史记录(当前使用 Hibernate Envers)。
  • 我们必须通过公司的网络安全团队批准任何新的依赖项/库。在我们等待批准期间,这可能会导致生产中断数天。为项目请求新的依赖项并不理想。
  • 目前没有办法处理 Excel 文件。API 调用或简单的数据库查询会很好,但出于安全原因,这不是我们的选择。
  • 可扩展性是一个日益受到关注的问题。该项目下的另一个团队必须解析一个 50K 行和 100 行的 Excel 文件。所有这些只是美国的数据。项目所有者表示,该公司最终希望将这款应用的管理能力扩展到国外。

我的想法

纯粹关于暂存问题,我认为最好摆脱负责暂存的 Hibernate 实体。我将使用存储过程将暂存数据迁移到 SQL 中的活动表中。尽管它是特定于供应商的(据我所知,无论如何),我将使用 Postgres 的 COPY 命令来处理大量行的繁重工作。我可以重写解析器以将数据定向到 CSV 或其他分隔文件。我唯一的问题是如何将数据迁移到使用 Hibernate 序列和生成器的表中。在像这样手动更新数据库后,我还没有弄清楚如何同步 Hibernate 的序列。它喜欢关于重复主键的抛出错误,直到它遇到未使用的序列中的 ID。但我觉得这完全是另一个问题。

编辑1:

我应该澄清一下。15 分钟是所有分期的总时间。这包括分期和迁移。仅 25K 记录的分期大约需要 1:30,这也不理想。我已经运行了几次会话指标,并为 Spring Data 保留了 25K 记录解决了以下数字:

2451000 nanoseconds spent acquiring 1 JDBC connection;
0 nanoseconds spent releasing 0 JDBC connections;
96970800 nanoseconds spent preparing 24851 JDBC statements;
9534006000 nanoseconds spent executing 24849 JDBC statements;
21666942900 nanoseconds spent executing 830 JDBC statements;
23513568700 nanoseconds spent executing 2 flushes (flushing a total of 49696 entities and 0 collections)
211588700 nanoseconds spent executing 1 partial-flushes (flushing a total of 24848 entities and 24848 collections)

对于这种特定情况,我正在暂存大约 25K 实体,然后使用存储过程仅将员工数据从暂存表移动到实时表(占总时间 15 分钟的一小部分)。该程序似乎立即运行。但是还有其他数据我们必须通过连接、group by 语句等来确定,这似乎很昂贵。我只是不确定为什么 Spring Data 需要这么长时间来保存这么多记录,而纯 SQL 需要的时间要少得多。

4

0 回答 0