Pregunta

El implementando-result-paging-in- La pregunta de hibernación-obtención-número-total-de-filas desencadena otra pregunta para mí, sobre alguna preocupación de implementación :

¿Ahora sabe que debe reutilizar parte de la consulta HQL para realizar el recuento, cómo reutilizarlo de manera eficiente?

Las diferencias entre las dos consultas HQL son:

  1. la selección es count (?) , en lugar del pojo o propiedad (o lista de)
  2. las recuperaciones no deberían ocurrir, por lo que algunas tablas no deberían unirse
  3. el orden por debería desaparecer

¿Hay otras diferencias?

¿Tiene las mejores prácticas de codificación para lograr esta reutilización de manera eficiente (inquietudes: esfuerzo, claridad, rendimiento)?

Ejemplo para una consulta HQL simple:

    select       a     from A a join fetch a.b b where a.id=66 order by a.name
    select count(a.id) from A a                  where a.id=66

ACTUALIZADO

Recibí respuestas en:

  • utilizando Criterios (pero usamos HQL principalmente)
  • manipulando la cadena (pero todos están de acuerdo en que parece complicado y no muy seguro)
  • envolviendo la consulta , confiando en la optimización de la base de datos (pero existe la sensación de que esto no es seguro)

Esperaba que alguien diera opciones en otro camino, más relacionado con la concatenación de cadenas.
¿Podríamos construir ambas consultas HQL usando partes comunes ?

¿Fue útil?

Solución

Buena pregunta. Esto es lo que he hecho en el pasado (muchas cosas que ya mencionaste):

  1. Comprueba si la cláusula SELECCIONAR está presente.
    1. Si no lo está, agregue seleccione conteo (*)
    2. De lo contrario, compruebe si tiene DISTINTO o funciones agregadas en él. Si está utilizando ANTLR para analizar su consulta, es posible solucionarlos, pero es bastante complicado. Probablemente esté mejor simplemente envolviendo todo con select count (*) from () .
  2. Eliminar obtener todas las propiedades
  3. Elimina fetch de las combinaciones si estás analizando HQL como una cadena. Si realmente está analizando la consulta con ANTLR puede eliminar left join por completo; es bastante complicado comprobar todas las referencias posibles.
  4. Eliminar orden por
  5. Dependiendo de lo que haya hecho en 1.2, deberá eliminar / ajustar el grupo por / tener .

Lo anterior se aplica a HQL, naturalmente. Para las consultas de Criterios, está bastante limitado con lo que puede hacer porque no se presta a la manipulación fácilmente. Si está utilizando algún tipo de capa de envoltorio encima de los Criterios, obtendrá un equivalente de un subconjunto (limitado) de los resultados del análisis ANTLR y podría aplicar la mayoría de los anteriores en ese caso.

Como normalmente mantendrías el desplazamiento de tu página actual y el recuento total, normalmente ejecuto la consulta real con el límite / desplazamiento dado primero y solo ejecuto la consulta count (*) si el número de resultados devueltos es más o igual que el límite Y el desplazamiento es cero (en todos los demás casos, o bien he ejecutado el count (*) antes o he recuperado todos los resultados de todos modos). Este es un enfoque optimista con respecto a las modificaciones concurrentes, por supuesto.

Actualizar (en HQL de ensamblaje manual)

No me gusta particularmente ese enfoque. Cuando se asigna como consulta con nombre, HQL tiene la ventaja de la verificación de errores en tiempo de compilación (bueno, técnicamente, el tiempo de ejecución, porque SessionFactory tiene que compilarse, aunque generalmente se realiza durante las pruebas de integración). Cuando se genera en el tiempo de ejecución, falla en el tiempo de ejecución :-) Hacer optimizaciones de rendimiento tampoco es exactamente fácil.

El mismo razonamiento se aplica a los criterios, por supuesto, pero es un poco más difícil de arruinar debido a una API bien definida en lugar de concatenación de cadenas. La creación de dos consultas HQL en paralelo (una paginada y "conteo global") también conduce a la duplicación de código (y posiblemente a más errores) o lo obliga a escribir algún tipo de capa de envoltorio en la parte superior para que lo haga por usted. Ambas formas están lejos de ser ideales. Y si necesita hacer esto desde el código del cliente (como en over API), el problema se agrava aún más.

En realidad he he reflexionado bastante sobre este problema. La API de búsqueda de Hibernate-Generic-DAO parece un compromiso razonable; hay más detalles en mi respuesta a la pregunta vinculada anterior.

Otros consejos

¿Ha intentado aclarar sus intenciones a Hibernate al establecer una proyección en sus criterios (SQL)? En su mayoría, he estado utilizando los Criterios, por lo que no estoy seguro de qué tan aplicable es su caso, pero lo he estado usando

getSession().createCriteria(persistentClass).
setProjection(Projections.rowCount()).uniqueResult()

y dejando que Hibernate descubra el almacenamiento en caché / reutilización / cosas inteligentes por sí solo ... No estoy realmente seguro de cuánta cosa inteligente realmente hace ... ¿Alguien quiere comentar sobre esto?

Bueno, no estoy seguro de que esta sea la mejor práctica, pero es mi práctica :)

Si tengo como consulta algo como:

select A.f1,A.f2,A.f3 from A, B where A.f2=B.f2 order by A.f1, B.f3

Y solo quiero saber cuántos resultados obtendré, lo ejecuto:

select count(*) from ( select A.f1, ... order by A.f1, B.f3 )

Y luego obtenga el resultado como un Integer, sin asignar los resultados en un POJO.

Analice su consulta para eliminar algunas partes, como "ordenar por" es muy complicado. Un buen RDBMS optimizará su consulta para usted.

Buena pregunta.

En una situación de HQL a mano alzada, usaría algo como esto pero esto no es reutilizable ya que es bastante específico para las entidades dadas

Integer count = (Integer) session.createQuery("select count(*) from ....").uniqueResult();

Haz esto una vez y ajusta el número de inicio según corresponda hasta que hagas la página.

Para los criterios, aunque uso una muestra como esta

final Criteria criteria = session.createCriteria(clazz);  
            List<Criterion> restrictions = factory.assemble(command.getFilter());
            for (Criterion restriction : restrictions)
                criteria.add(restriction);
            criteria.add(Restrictions.conjunction());
            if(this.projections != null)
                criteria.setProjection(factory.loadProjections(this.projections));
            criteria.addOrder(command.getDir().equals("ASC")?Order.asc(command.getSort()):Order.desc(command.getSort()));
            ScrollableResults scrollable = criteria.scroll(ScrollMode.SCROLL_INSENSITIVE);
            if(scrollable.last()){//returns true if there is a resultset
                genericDTO.setTotalCount(scrollable.getRowNumber() + 1);
                criteria.setFirstResult(command.getStart())
                        .setMaxResults(command.getLimit());
                genericDTO.setLineItems(Collections.unmodifiableList(criteria.list()));
            }
            scrollable.close();
            return genericDTO;

Pero esto hace el recuento cada vez que se llama ScrollableResults: last () .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top