如何有效地查询三个相关表(JPA-QL)

时间:2009-10-12 13:22:16

标签: optimization jpa join

假设我有实体A,B,C,每个A有很多B和C实体。我想根据一些criterea来查询A个实体的加载,我知道我将访问每个A返回的所有B和C实体。

select a from A as a join fetch a.b join fetch a.c这样的东西一开始似乎有意义,但如果B和C实体的数量很大,这会产生巨大的产品。将此扩展到另一个关联实体会使查询完全不合理。

如果我将JPA留给自己的设备,当我想访问B和C实体时,我最终会选择n + 1。

我认为我要做的是查询A连接提取B,然后连接提取C,但这不起作用,因为它给了我两个List<A>结果,每个结果只有一半信息。

这是一个非常简单的SQL查询,我很失望没有一种明显的方法来处理这个问题。我错过了什么吗?

提供商是toplink essentials

2 个答案:

答案 0 :(得分:1)

JPA至少应该提到对象。事实上,你并没有告诉我你不会充分利用JPA。

如果您有遗留架构,并且对象模型没有意义,那么您可能不应该使用JPA。

JPA并不打算替代SQL。它解决了对象关系不匹配问题。如果您没有对象,只需下拉到JDBC和SQL。

我不知道你的表代表什么,但是如果你正在考虑对象,你应该谈论1:m和m:n关系。一旦你有了那些,你可以使用缓存,懒惰和渴望获取来优化填充对象。

更新:编写查询,以便每个产品的选项和价格列表为1:m关系并进行急切提取。这将避免(n + 1)问题。

你怎么能说关系和热切的提取在这里没有帮助?

尝试表达对象中的关系,让JPA向您展示它生成的SQL,并将其与您编写的内容进行比较。如果它是令人满意的,那就去吧。如果没有,请下拉到JDBC,看看能否做得更好。

答案 1 :(得分:0)

我想知道为什么你说这在SQL术语中非常简单。你不也有笛卡儿产品吗?


使用JPA的Hibernate提供程序,您提到的选项有效:

  

查询连接提取B,然后是连接提取C

你有两个相同值的列表,你只使用一个,它很好(你只需要左边连接)。


在Hibernate中,您还可以要求在第二个查询中获取丢失的数据。

使用fetch="subselect"

请参阅https://www.hibernate.org/315.html


在原始海报评论后

更新

在java中,您也可以手动执行此操作

  1. 在名为entityAs的列表中获取带有B的集合的As。
  2. 使用他们的Cs集合获取As(重用部分查询或使用ID)。
  3. 创建数据结构地图&gt;对于第二个查询(为了性能,避免内循环)。
  4. 循环列表entityAs,使用Map为每个实例A设置集合C.
  5. 这也会有很好的表现。

    如果您多次运行此需求,您可以编写一个参数化方法来为您执行此操作,因此您只需编写一次代码。

      

    正如原始海报评论的那样,您需要在修改它们之前从entityAs分离所有A实体,以确保不会向数据库发送更新......