Spring数据查询执行优化:JpaRepository中Hibernate@Query方法的并行执行

Spring Data Query Execution Optimization: Parallel Execution of Hibernate @Query Method in JpaRepository

我有一个仪表板视图,它需要来自整个数据库表的小数据集。我优化了数据库查询(例如删除了子查询)。现在大约有 20 个查询一个接一个地执行,并且从数据库中获取不同的数据集。大多数 HQL 查询包含 GROUP BYJOIN 子句。用SpringREST接口,将结果返回给前端。

如何优化自定义查询的执行?我最初的想法是 运行 并行查询数据库。但我该如何实现呢?在做了一些研究之后,我发现了注解 @Async ,这使得并行 运行 方法成为可能。但这对 Hibernate 方法有效吗?在 JpaRepository 中是否总是为每个用 @Query 注释的方法创建一个新的数据库会话? 运行执行数据库查询对整体执行时间有影响吗?

并行 运行 数据库调用的另一种方法是将仪表板调用拆分为几个单独的 Ajax 调用(每个问题都有自己的 Ajax 调用)。我不想这样做,因为每次打开仪表板(或例如更改日期范围)时,都会进行另外 20 Ajax 次调用以获取新数据。同样的问题仍然存在:Does 运行ning SQL queries in parallel have a effect on the execution time of the database?

我目前还没有向数据库添加额外的索引。这将是下一件事,我肯定会做。但是,我对 运行 并行查询的性能影响以及如何使用 Spring.

以编程方式实现这一点很感兴趣

我的项目最初是由 jHipster 生成的(Spring Boot、MariaDB、AngularJS 等)

首先,运行这些SQL并行不会对数据库造成影响,只会让页面加载速度变快,所以设计要着重于此。

我发布此答案时假设您已经确定不能合并这 20 个 SQL,因为数据不相关(没有连接、视图等)。

出于两个原因,我建议不要使用@Async。

原因 1 - 当您想触发一堆任务然后忘记时,或者当您知道所有任务何时完成时,异步任务非常有用。因此,您需要 "wait" 才能完成所有异步任务。你应该等多久?直到完成最慢的查询?

检查异步示例代码(来自指南@spring.io --https://spring.io/guides/gs/async-method/

// Wait until they are all done
while (!(page1.isDone() && page2.isDone() && page3.isDone())) {
     Thread.sleep(10); //10-millisecond pause between each check
}

Will/should 您的服务组件等待 20 个 Async DAO 查询?

原因 2 - 请记住,异步只是将任务作为线程产生。由于您要使用 JPA,请记住实体管理器不是线程安全的。 DAO 类 将传播事务。这是可能出现的问题示例 - http://alexgaddie.blogspot.com/2011/04/spring-3-async-with-hibernate-and.html

恕我直言,最好继续进行多次 Ajax 调用,因为这会使您的组件具有内聚性。是的,你将有 20 个端点,但它们将有一个更简单的 DAO,更简单的 SQL,易于单元测试并且返回的数据结构将更容易被 AngularJS 小部件handle/parse。当 UI 触发所有 20 个 Ajax 调用时,仪表板将在准备就绪时加载各个小部件,而不是同时加载所有小部件。这将帮助您在未来通过优化仪表板较慢的加载部分(可能是缓存、索引等)来扩展您的设计。

捆绑您的 DAO 调用只会使数据结构变得复杂并且单元测试更加困难。

通常并行执行查询会快得多。如果您正在使用 Spring 数据并且没有配置任何特定的内容,您的 JPA 提供程序 (Hibernate) 将创建一个连接池来存储与您的数据库的连接。我认为默认情况下,Hibernate 拥有 10 个连接,这样做可以并行执行 10 个查询。 运行 并行查询的速度取决于数据库和表/查询的结构。 我认为使用 @Async 并不是这里的最佳实践。定义 20 个提供特定查询结果的 REST 端点是一种更好的方法。通过这样做,您可以简单地为每个查询创建实体、存储库和 RestEndpoint class。通过这样做,每个查询都是独立的,并且代码不那么复杂。