Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 防止JPA中的N+1选择_Java_Sql_Performance_Jpa - Fatal编程技术网

Java 防止JPA中的N+1选择

Java 防止JPA中的N+1选择,java,sql,performance,jpa,Java,Sql,Performance,Jpa,我有JPA实体订单,与客户有多通关系。它是双向的,所以客户也有一个单一的领域订单。这两种关系都使用即时抓取或在OpenJPA抓取计划中 当我从订单中选择时,我为订单得到1个select,为Customer.orders字段得到N个select。令我惊讶的是,OpenJPA、EclipseLink和Hibernate都存在这个问题,即使我使用的是JOIN FETCH,它在单向情况下也能工作 有没有解决这个问题的好办法? 对于更复杂的图,有没有解决N+1选择问题的解决方案 编辑:我自己的研究结果:

我有JPA实体订单,与客户有多通关系。它是双向的,所以客户也有一个单一的领域订单。这两种关系都使用即时抓取或在OpenJPA抓取计划中

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

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

编辑:我自己的研究结果: -对于我正在使用的OpenJPA,我还不知道解决方案 -对于Hibernate@fetchmode.SUBSELECT解决了这个问题。使用@BatchSize也有帮助,它可以同时选择给定数量的customer.orders字段。
-对于EclipseLink,我发现了一个类似的特性@BatchFetchvalue=BatchFetchType.IN,但在这种情况下它没有帮助,我认为它不能在双向关系中有效地处理这个问题。

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

看看:因为那里有很多好信息

如果您正在使用Hibernate:

这是因为一般来说,N+1选择问题主要是批处理问题。否则,延迟加载(通常为N+1)解决方案可能有助于提高性能。

以下是一个解决方案:

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

从实体中完全删除关系

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

在查询执行期间,像通常一样收集父对象

基于FK to parent PK,使用带IN子句的命名参数化查询检索整个子级集合

循环浏览结果并将其与家长匹配


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

这是一个有点杂乱无章的问题。您是否有一个特定的问题需要帮助,或者您只是想抱怨JPA?您是对的,我对JPA感到有点失望,我将对我的问题进行编辑,使其更切题。您真的需要急切地获取客户订单吗?@Esteve您的观点很好。在制作订单及其客户的简单列表时,您实际上不需要这些客户的任何其他订单!不过,在其他情况下,您可能确实需要加载这样的字段,我认为在不使用N+1 selectThank you的情况下也可以选择这样的字段。使用本机查询肯定会有所帮助。但这让人觉得您必须手工编写一些应该由ORM负责执行的内容。这可能会导致大量的手工工作和维护噩梦。@SlowStrider的想法是你不应该经常这样做。N+1延迟加载通常是解决大多数问题的正确方法。此外,当谈到像这样的性能可靠优化时,您会发现SQL而不是JPA HQL是您唯一的选择。。。所以,除非你必须这样做,否则不要这样做。如果你能告诉我为什么,对那些失败的选民会有帮助。N+1选择问题无法神奇地解决。您可以使用字段的笛卡尔乘积,也可以延迟加载每个对象。我不知道人们在期待什么。没有一个该死的ORM可以预测数据库性能,并随机决定何时做渴望的笛卡尔积和懒惰的N+1。我不知道人们在期待什么。很抱歉,我不能提供一个剪切粘贴的代码来解决这个问题。我认为投票失败的原因是你说n+1延迟加载通常是正确的方式。我不同意。。。实际上,我认为JPA的集合映射常常适得其反。只需启动一个单独的非本机查询,即可获得customerId=。。。。不管怎么说,我还是不认为投反对票是合理的。