mvc - Hibernate-paginación HQL
pageable spring example (5)
Este es un problema similar a: HQL - identificador de fila para paginación
Estoy tratando de implementar la paginación utilizando HQL. Tengo una base de datos PostgreSQL.
int elementsPerBlock = 10;
int page = 2; //offset = 2*10
String sqlQuery = "FROM Messages AS msg " +
" LEFT JOIN FETCH msg.commands AS cmd " +
"ORDER BY msg.identifier ASC" ;
Query query = session.createQuery( sqlQuery )
.setFirstResult( elementsPerBlock * ( (page-1) +1 ) )
.setMaxResults( elementsPerBlock );
Lo que sucede es que Hibernate recupera TODOS los mensajes y devuelve los necesarios una vez que se cargaron.
Por lo tanto, Hibernate obtiene 210000 entidades en lugar de las 30 que se devuelven (cada Mensaje tiene exactamente 2 comandos).
¿Hay una manera de reducir la sobrecarga en un factor de 7000?
edición: he .setFetchSize( elementsPerBlock )
agregar .setFetchSize( elementsPerBlock )
. No sirvió de nada.
edit 2: la consulta SQL que se genera es:
select ...
from schemaName.messages messages0_
left outer join schemaName.send_commands commands1_
on messages0_.unique_key=commands1_.message_key
order by messages0_.unique_identifier ASC
Absolutamente no hay límite o compensación
Dado que no filtra el conjunto de resultados con respecto a algunos atributos de la entidad de comando , también puede evitar la unión a SQL y configurar la búsqueda perezosa para los comandos del mensaje . Sin unirse, Hibernate empleará las capacidades de paginación de la base de datos.
Sin embargo, debe preocuparse por el problema de selección de N + 1 , es decir, evitar una sola selección para cada atributo de comandos de búsqueda perezosa. Puede evitar esto configurando la propiedad de tamaño de lote en su asignación de hibernación o globalmente la propiedad hibernate.default_batch_fetch_size en su configuración de hibernación.
Por ejemplo: si ha recuperado 100 objetos de mensaje dentro de una sesión de Hibernate y ha establecido un tamaño de lote de 10, Hibernate buscará 10 asociaciones de comandos de 10 objetos de mensaje diferentes cuando llame a getCommands () de un objeto de mensaje . El número de consultas se reduce a 10 más el original de búsqueda de mensajes.
Eche un vistazo aquí: http://java.dzone.com/articles/hibernate-tuning-queries-using?page=0,1 El autor compara las diferentes estrategias de búsqueda para un ejemplo simple
Estoy usando esta solución:
/**
* @param limitPerPage
* @param page
* @return
*/
public List<T> searchByPage(int limitPerPage, int page, String entity) {
String sql = "SELECT t FROM " + entity + " t";
Query query = em.createQuery(sql)
.setFirstResult(calculateOffset(page, limitPerPage))
.setMaxResults(limitPerPage);
return query.getResultList();
}
/**
* @param page
* @return
*/
private int calculateOffset(int page, int limit) {
return ((limit * page) - limit);
}
Bienvenido.
Podemos lograr la paginación utilizando la interfaz de Consulta y Criterios :
Paginación usando la interfaz de consulta:
Hay dos métodos de la interfaz de consulta para la paginación.
1. Query setFirstResult (int startPosition): este método toma un entero que representa la primera fila de su conjunto de resultados, comenzando con la fila 0.
2. Query setMaxResults (int maxResult): este método le dice a Hibernate que recupere un número fijo de maxResults de objetos. Usando los dos métodos anteriores juntos, podemos construir un componente de paginación en nuestra aplicación web o Swing.
Ejemplo:
Query query = session.createQuery("FROM Employee");
query.setFirstResult(5);
query.setMaxResults(10);
List<Employee> list = query.list();
for(Employee emp: list) {
System.out.println(emp);
}
Paginación utilizando Interfaz de Criterios:
Hay dos métodos de la interfaz de criterios para la paginación.
1. Criterios setFirstResult (int firstResult):
Establecer el primer resultado que se recuperará.
2. Lista de elementos Criterios setMaxResults (int maxResults):
Establezca un límite en el número de objetos que se recuperarán.
Ejemplo:
Criteria criteria = session.createCriteria(Employee.class);
criteria.setFirstResult(5);
criteria.setMaxResults(10);
List<Employee> list = criteria.list();
for(Employee emp: list) {
System.out.println(emp);
}
Probablemente, si crea su propia consulta con HQL, los métodos del generador de consultas no pueden analizar y modificar la consulta hql personalizada. Por lo tanto, debe poner su LIMIT ?, ?
Declaración al final de su consulta HQL y vincular los parámetros de compensación entonces.
Según la especificación JPA 2.0 , sección 3.8.6 Ejecución de consultas,
El efecto de aplicar setMaxResults o setFirstResult a una consulta que involucra la obtención de uniones sobre colecciones no está definido.
Varía de una base de datos a otra, y en mi experiencia, el resultado es que Hibernate generalmente realiza la paginación en la memoria en lugar de hacerlo en el nivel de consulta de la base de datos.
Lo que normalmente hago es usar una consulta separada para obtener los identificadores de los objetos deseados, y pasar eso a la consulta con la combinación de búsqueda.