首页 > 解决方案 > 使用 JPA 解决 N+1 查询问题时的问题

问题描述

先决条件

我有以下数据库结构:

  1. 表列表包括 A、B、C、D 和 E
  2. 所有这些表都有一个 BIGINT 主键
  3. 表 A 代表基本实体
  4. 表 B、C 和 D 包含表 A 的外键,本质上是从 A 创建 1:N 关系
  5. 表 E 有一个外键引用表 D,即表 D 的 1:N 关系
  6. 所有外键都被索引

问题描述

这里的目标是能够在给定几个文件管理器的情况下使用 JPA 获取具有所有引用实体的基本实体where

以前,我依赖于 OSIV 过滤器。因此,在查询时,正在查询没有被引用实体的基本实体,并且在视图层,当 Jackson 尝试访问 getter 以制定响应时,正在执行额外的查询以获取引用的实体。如您所见,这导致了所谓的 N+1 查询问题。此外,作为基本查询的一部分,为分页设置了偏移量和限制。

为了解决 N+1 查询问题,同时确保分页发生在数据库级别而不是应用程序级别的内存中,我执行了以下操作:

  1. 执行的第一个查询是从表 A 中检索与过滤器匹配的不同 id,按参数排序,并进行分页。
select distinct id from A 
left join B on B.a_id = A.id
left join C on C.a_id = A.id
left join D on D.a_id = A.id
left join E on E.d_id = D.id
where A.attribute_1 = ? and B.attribute_2 = ? ...
  1. 执行的第二个查询是检索完整的 JPA 实体 A,其中包括所有引用的实体,其中 id 是从查询 1 中检索到的 id 之一
select * from A 
left outer join B on B.a_id = A.id
left outer join C on C.a_id = A.id
left outer join D on D.a_id = A.id
left outer join E on E.d_id = D.id
where A.id in (:ids)

问题

我面临的问题是发布此优化后,令人惊讶的是性能已显着下降。需要注意的是,查询#2 会导致性能下降。一个观察结果是,随着 C 中的条目增加,查询 #2 正在进一步减慢。过去有没有人遇到过类似的问题,或者如果我做错了什么,请帮助让我知道解决方案。

标签: javamysqlhibernatejpamicroservices

解决方案


推荐阅读