在JPA中阻止N + 1选择

时间:2012-11-15 15:07:10

标签: java sql performance jpa

我有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,我发现了一个类似的功能@BatchFetch(value = BatchFetchType.IN),但在这种情况下没有帮助,我想它无法在双向关系中有效地处理这个问题。

3 个答案:

答案 0 :(得分:2)

请看一下:What is SELECT N+1?因为那里有很多好消息。

如果你使用Hibernate:Hibernate - Chapter 19: Improving Performance - Fetching Strategies

My own personal solution is to use native SQL and tmp ids table这是因为一般恕我直言N + 1选择问题主要是批量处理的问题。否则延迟加载(通常是N + 1解决方案)可能有利于性能。

答案 1 :(得分:0)

这是一个解决方案:

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

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

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

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

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

  6. 循环搜索结果并将其与父母匹配。

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

答案 2 :(得分:-1)

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