7

我有 JPA 实体 Order 与客户的多对一关系。它是双向的,因此 Customer 也有一个 OneToMany 字段的订单。两种关系都使用 EAGER 获取(或在 OpenJPA 获取计划中)。

当我从 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) 但在这种情况下它没有帮助,我想它不能在双向关系中有效地处理这个问题。

4

3 回答 3

1

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

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

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

于 2012-11-15T15:50:54.250 回答
0

这是一个解决方案:

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

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

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

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

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

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

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

于 2016-10-15T16:19:15.513 回答
-1

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

于 2012-11-15T15:42:06.347 回答