gpt4 book ai didi

hibernate - org.hibernate.hql.ast.QueryTranslatorImpl 列表注意 : firstResult/maxResults specified with collection fetch; applying in memory

转载 作者:行者123 更新时间:2023-12-03 23:10:27 25 4
gpt4 key购买 nike

我遇到了一个问题,我在 JPA 中有一个查询。因为我有一些集合,所以我需要使用左连接提取或内连接提取

我的问题是使用 setFirstResultsetMaxResult为了带回精确数量的结果。每次我看到整个结果都会带回来,并且只有在使用 maxResult 之后。

有什么办法可以使 maxResult 之前?

非常感谢 !

这是更多信息:

我的问题是当我使用它时:

startIndex = 0;
maxResults = 10;
query.setFirstResult(startIndex);
query.setMaxResults(maxResults);

我在日志中看到此消息:

7 juin 2011 09:52:37 org.hibernate.hql.ast.QueryTranslatorImpl list ATTENTION: firstResult/maxResults specified with collection fetch; applying in memory!



我看到 200 个结果返回(在日志中),在 HashSet 之后,我终于得到了我要求的 10 个结果。

它在内存中似乎是带回 200 结果并在 maxResults 应用于内存之后。

我正在搜索是否有任何方法可以获取和限制结果的数量。

我使用了一种解决方法,我进行了第一个查询以询问我的订单的 id,没有任何提取,使用了 maxResult。
一切正常,它使用了限制指令。
在我使用我的“大”查询和 fetch 并将结果限制在 id 列表中后,带回第一个。

这是我没有解决方法的完整查询(请注意,@Bozho 的谈话没有产生限制):

select o from Order  o
left join fetch o.notes note
left join fetch o.orderedBy orderedBy
left join fetch orderedBy.address addressOrdered
left join fetch orderedBy.language orderedByLg
left join fetch orderedByLg.translations orderedByLgTtrad
left join fetch o.deliveredTo deliveredTo
left join fetch deliveredTo.address addressDelivered
left join fetch deliveredTo.language deliveredToLg
left join fetch deliveredToLg.translations
left join fetch o.finalReceiptPlace finalReceiptPlace
left join fetch finalReceiptPlace.address addressFinalReceiptPlace
left join fetch finalReceiptPlace.language finalReceiptPlaceLg
left join fetch finalReceiptPlaceLg.translations
inner join fetch o.deliveryRoute delivery
left join fetch delivery.translations
inner join fetch o.type orderType
left join fetch orderType.translations
inner join fetch o.currency currency
left join fetch currency.translations
left join fetch o.attachments
left join fetch note.origin orig
left join fetch orig.translations
left join fetch o.supplier sup
left join fetch sup.department dep
left join fetch o.stateDetail stateD
inner join fetch stateD.state stat
where 1=1 and o.entryDate >= :startDat

最佳答案

TL;DR Hibernate doesn't know how many rows of the flattened, joined query it needs to get the specified number of the Order objects, so it has to load the whole query in memory. See below for an explanation.



要理解 Hibernate 为什么这样做,您需要了解 Hibernate 如何执行 JPA 实体所涉及的 ORM(对象关系映射)。

为您的订单考虑一组简化的实体。类(class) Order包含 2 个字段: numbercustomerId和订单行列表。类(class) OrderLine包含 productCodequantity字段,以及 uid键和对父订单的引用。

这些类可以这样定义:
@Entity
@Table(name = "ORDER")
public class Order {
@ID
@Column(name = "NUMBER")
private Integer number;
@Column(name = "CUSTOMER_ID")
private Integer customerId;
@OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
@OrderBy
private List<OrderLine> orderLineList;

.... // Rest of the class
}

@Entity
@Table(name = "ORDER_LINE")
public class OrderLine
{
@ID
@Column(name = "UID")
private Integer uid;
@Column(name = "PRODUCT_CODE")
private Integer productCode;
@Column(name = "QUANTITY")
private Integer quantity;
@Column(name = "ORDER_NUMBER")
private Integer orderNumber;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "ORDER_NUMBER", referencedColumnName = "NUMBER", insertable = false, updatable = false)
private Order order;

.... // Rest of the class
}

现在,如果您对这些实体执行以下 JPQL 查询:
SELECT o FROM Order o LEFT JOIN FETCH o.orderLineList

然后 Hibernate 将此查询作为类似于以下内容的“扁平化”SQL 查询执行:
SELECT o.number, o.customer_id, ol.uid, ol.product_code, ol.quantity, ol.order_number
FROM order o LEFT JOIN order_line ol ON order_line.order_number = order.number

这将给出这样的结果:
| o.number | o.customer_id | ol.uid | ol.product_code | ol.quantity |
|==========|===============|========|=================|=============|
| 1 | 123 | 1 | 1111 | 5 |
| 1 | 123 | 2 | 1112 | 6 |
| 1 | 123 | 3 | 1113 | 1 |
| 2 | 123 | 4 | 1111 | 2 |
| 2 | 123 | 5 | 1112 | 7 |
| 3 | 123 | 6 | 1111 | 6 |
| 3 | 123 | 7 | 1112 | 5 |
| 3 | 123 | 8 | 1113 | 3 |
| 3 | 123 | 9 | 1114 | 2 |
| 3 | 123 | 10 | 1115 | 9 |
...etc

Hibernate 将使用它来“重建” Order带有 OrderLine 附加列表的对象子对象。

但是,由于每个订单的订单行数是随机的,Hibernate 没有办法知道这个查询需要多少行才能得到指定的最大数量 Order需要的对象。因此,在丢弃结果集的其余部分之前,它必须采用整个查询并在内存中构建对象,直到它具有正确的数量。它产生的日志警告暗示了这一点:
ATTENTION: firstResult/maxResults specified with collection fetch; applying in memory!

我们现在才刚刚发现这些查询会对服务器内存使用产生重大影响,并且我们在尝试这些查询时遇到了服务器因内存不足错误而崩溃的问题。

顺便说一句,我现在要说的是,这主要只是我的理论,我不知道实际的 Hibernate 代码是如何工作的。当您让 Hibernate 记录它生成的 SQL 语句时,您可以从日志中收集大部分信息。

更新:
最近我发现了上面的一个小问题。

考虑第三个名为 Shipment 的实体这是一个或多个订单行。
Shipment实体将有一个 @ManyToOneOrder 的关联实体。

假设您有 4 个行的同一个订单有 2 个发货。

如果您对以下内容执行 JPQL 查询:
SELECT s FROM Shipment s LEFT JOIN s.order o LEFT JOIN FETCH o.orderLineList

您会期望(或至少我做到了)取回 2 个装运对象,每个对象都引用同一个 Order 对象,该对象本身将包含 4 行。

不对,又错了!实际上,您会得到 2 个 Shipment 对象,每个对象都指向同一个 Order 对象,其中包含 8 线!是的,线条在订单中被复制了!是的,即使您指定 DISTINCT 子句也是如此。

如果您在 SO 或其他地方(最显着的 Hibernate 论坛)上研究这个问题,您会发现这实际上是一个功能,而不是一个错误,根据 Hibernate 的权力。有些人居然 想要这种行为!

去搞清楚。

关于hibernate - org.hibernate.hql.ast.QueryTranslatorImpl 列表注意 : firstResult/maxResults specified with collection fetch; applying in memory,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6258556/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com