hibernate - example - jpa ejemplos
org.hibernate.hql.ast.QueryTranslatorImpl list ATENCIÓN: firstResult/maxResults especificado con obtención de recopilación; aplicando en la memoria (3)
Estoy enfrentando un problema, tengo una consulta en JPA. como tengo algunas colecciones, necesito usar la búsqueda de unión izquierda o la búsqueda de unión interna
Mi problema es usar setFirstResult
y setMaxResult
para traer de vuelta un número preciso de resultados. cada vez que veo el resultado completo, vuelvo y solo DESPUÉS de que se use maxResult.
¿Hay alguna forma de hacer el maxResult antes?
Muchas gracias !
aquí hay más información:
mi problema es cuando uso eso:
startIndex = 0;
maxResults = 10;
query.setFirstResult(startIndex);
query.setMaxResults(maxResults);
Veo este mensaje en mi registro:
7 juin 2011 09:52:37 org.hibernate.hql.ast.QueryTranslatorImpl list ATENCIÓN: firstResult / maxResults especificado con la recuperación de recopilación; aplicando en la memoria!
Veo el resultado de 200 volver (en el registro) y después en el HashSet tengo finalmente los 10 resultados que pido.
su parece en la memoria es devolver el resultado de 200 y después de que se aplique maxResults en la memoria.
Estoy buscando si hay alguna manera de poder buscar y limitar el número de resultados.
Utilicé una solución alternativa, realicé una primera consulta para solicitar el ID de mi pedido, sin ninguna búsqueda, utilicé el maxResult. todo funciona perfectamente, se usa la instrucción límite. Después de usar mi consulta "grande" con la búsqueda y limitar el resultado dentro de la lista de identificación traer de vuelta en la primera.
aquí está mi consulta completa sin mi solución alternativa (observe que no hay límite generado como conversación por @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
setMaxResult (10) ajusta la consulta con otro resultado limitante, por ejemplo, para el oráculo:
seleccione * de ("su consulta aquí") donde rownum <10
Descubrí esto hoy durante la investigación de la consulta que tomó 64 segundos, ahora, lleva 1 segundo.
... lo mismo para criteria.setProjection (Projections.rowCount ()). setMaxResults (10)
Depende del motor DB usado ...
Tengo el mismo problema con Derby DB setFirstResult
/ setMaxResults
no se utilizan.
ROW_NUMBER() OVER()...
parece ser la solución.
Desafortunadamente, no encuentro cómo puedo generar tales solicitudes con JPA sin especificar toda la solicitud en SQL.
Para entender por qué Hibernate hace esto, necesita comprender cómo Hibernate hace el ORM (mapeo relacional de objetos) involucrado para las entidades JPA.
Considere un conjunto simplificado de Entidades para su pedido. Class Order
contiene 2 campos: number
y customerId
y una lista de líneas de pedido. Class OrderLine
contiene los campos productCode
y quantity
, así como una clave de uid
y una referencia al pedido principal.
Estas clases se pueden definir así:
@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
}
Ahora, si realizó la siguiente consulta JPQL en estas Entidades:
SELECT o FROM Order o LEFT JOIN FETCH o.orderLineList
luego Hibernate realiza esta consulta como una consulta SQL ''aplanada'' similar a la siguiente:
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
que daría un resultado como este:
| 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
que Hibernate usaría para "reconstruir" objetos Order
con listas adjuntas de sub-objetos OrderLine
.
Sin embargo, dado que el número de líneas de pedido por pedido es aleatorio, no hay forma de que Hibernate sepa cuántas filas de esta consulta se deben realizar para obtener el número máximo especificado de objetos Order
. Por lo tanto, tiene que tomar toda la consulta y crear los objetos en la memoria hasta que tenga la cantidad correcta, antes de descartar el resto del conjunto de resultados. La advertencia de registro que produce alude a esto:
ATTENTION: firstResult/maxResults specified with collection fetch; applying in memory!
Recién ahora estamos descubriendo que estas consultas pueden tener un impacto significativo en el uso de la memoria del servidor, y hemos tenido problemas con nuestro servidor que se cae con errores de falta de memoria cuando se intentan estas consultas.
Por cierto, diré ahora que esto es mayormente teoría de mi parte y no tengo idea de cómo funciona el código real de Hibernate. La mayor parte de esto se puede obtener de los registros cuando Hibernate registra las declaraciones SQL que genera.
ACTUALIZACIÓN: Recientemente he descubierto un poco de ''gotcha'' con lo anterior.
Considere una tercera entidad llamada Shipment
que es para una o más líneas de una orden.
La entidad de Shipment
tendría una asociación @ManyToOne
con la entidad Order
.
Supongamos que tiene 2 envíos para la misma orden que tiene 4 líneas.
Si realiza una consulta JPQL para lo siguiente:
SELECT s FROM Shipment s LEFT JOIN s.order o LEFT JOIN FETCH o.orderLineList
Esperaría (o al menos yo lo hice) recuperar dos objetos de envío, cada uno con una referencia al mismo objeto Order, que a su vez contendría las 4 líneas.
¡No, mal otra vez! De hecho, obtienes 2 objetos de envío, cada uno refiriéndose al mismo objeto Order, que contiene 8 líneas. Sí, las líneas se duplican en el pedido. Y sí, incluso si especifica la cláusula DISTINCT.
Si investigas este tema aquí en SO o en otro lugar (más notablemente en los foros de Hibernate), encontrarás que esto es realmente una característica, no un error, de acuerdo con los poderes de Hibernate. ¡Algunas personas realmente quieren este comportamiento!
Imagínate.