防止JPA中的N + 1选择

我有JPA实体订单与Customer的ManyToOne关系。 它是双向的,因此Customer也有一个OneToMany字段订单。 这两个关系都使用EAGER获取(或者在OpenJPA fetchplan中)。

当我从Order中选择时,我得到1个订单选择,N选择Customer.orders字段。 令我惊讶的是,OpenJPA,EclipseLink和Hibernate存在这个问题,即使我使用JOIN FETCH(它确实在单向情况下工作)。

有没有好办法解决这个问题? 有没有解决更复杂图形的N + 1选择问题的解决方案?

编辑:我自己的研究结果: – 对于OpenJPA(我正在使用)我还不知道解决方案 – 对于Hibernate @Fetch(FetchMode.SUBSELECT)解决了这个问题。 使用@BatchSize也有帮助,它同时选择给定数量的customer.orders字段。 – 对于EclipseLink,我发现了一个类似的function@BatchFetch(value = BatchFetchType.IN)但在这种情况下没有帮助,我想它无法在双向关系中有效地处理这个问题。

看看: 什么是SELECT N + 1? 因为那里有很多好消息。

如果您使用Hibernate: Hibernate – 第19章:提高性能 – 获取策略

我自己的个人解决方案是使用本机SQL和tmp ids表 ,因为一般恕我直言N + 1选择问题主要是批处理问题。 否则延迟加载(通常是N + 1解决方案)可能有利于性能。

这是一个解决方案:

  1. 将实体层与API层分开,并仅在您的应用程序中与API实例交互。 在此上下文中的api也可以称为DTO。

  2. 完全从实体中删除关系。

  3. 创建一个机制来指示您希望获取子项。 例如:将fetchRequestList传播到将API映射到实体的层(这样您可以有条件地获取)。

  4. 在查询执行期间,像往常一样收集父对象。

  5. 使用带有IN子句的命名参数化查询检索整个子集合,该子句基于FK到父PK。

  6. 循环结果并将它们与父母匹配。

这将迫使ORM执行n + 1个查询而不是n(n + 1)个查询。 请记住,您现在必须使用自定义逻辑来实现级联保存,删除,更新等。

在任何ORM框架中,N + 1问题都很常见。 你无法避免这种情况。 但是,这更多的是关于你采取什么样的方法来解决问题。 您可以根据实施使用关联和延迟加载或急切加载日期。 您还可以在单​​个查询中执行数据库映射和getc所有关联数据,并将其映射到模型。 由于数据库已编制索引,因此此操作可能比使用N + 1查询获取数据和映射(如果您的网络延迟允许)更快。