Eficiencia Ejecutando Querys Con Hibernate

De Dos Ideas.
Saltar a: navegación, buscar

Hibernate Query

Hibernate provee varias formas de ejecutar un mismo Query HQL, devolviendo los resultados de distintas maneras. La interfaz que se utiliza para la ejecución de queries es precisamente org.hibernate.Query que provee 3 metodos para obtener los resultados de un Query: list(), iterate() y scroll().

Se analizarán los dos primeros en cuanto a eficiencia y conveniencia de uso.

Query.list()

El método Query.list() devuelve en una colección todos los resultados del Query. Es decir, en la colección se encuentran instanciadas todas las entidades que corresponden al resultado de la ejecución del HQL, por lo tanto el ResultSet subyacente de la conexión JDBC se cierra ya que no se necesita más.

Notar que esta alternativa realiza una única comunicación con la base de datos en donde se traen todos los resultados y requiere que haya memoria suficiente para almacenar todos los objetos resultantes del query. Si la cantidad de resultados es extensa, el delay del acceso a la base será notorio.

Ejemplo:

Query q = session.createQuery("from Auto auto where auto.aniocreacion < 1985 "); List autos = q.list();


Query.iterate()

El método Query.iterate() devuelve un iterador java.util.Iterator para iterar los resultados del query. En este caso, las entidades se instancian "a demanda", es decir, con cada llamada al método Iterator.next() que devolverá la entidad de la posición actual del iterador.

Para resolver esto, Hibernate ejecuta el query obteniendo sólo los ids de las entidades, y en cada llamada al método Iterator.next() ejecuta la consulta propia para obtener la entidad completa. Esto se traduce en una mayor cantidad de accesos a la base de datos, resultando en un mayor tiempo de procesamiento total. La ventaja de este método es que no se requiere que todas las entidades estén cargadas en memoria simultáneamente, consumiendo memoria innecesariamente.

Para optimizar la obtención de entidades haciendo que no se realice un acceso a la base por cada llamada al metodo Iterator.next(), se puede fijar la cantidad de resultados a traer en cada acceso o "fetch". Esto se configura llamando al método Query.setFetchSize() antes de la ejecución de la consulta.


Ejemplo:

Query q = session.createQuery("from Auto auto where auto.aniocreacion < 1985 "); q.setFetchSize(10); // se obtendrán 10 resultados en cada acceso a la base. Iterator iter = q.iterate(); while ( iter.hasNext() ) {

   Auto auto = (Auto) iter.next();  // fetch the object
   ...
   

}

Debe tenerse particular cuidado en que no se cierre la sesión de hibernate mientras se utiliza el iterador, de lo contrario no se podrán obtener los resultados subsiguientes de la base de datos.


Conclusión

Para los casos en que se deban tener acceso simultáneo a todas las entidades resultantes de un Query, el método Query.list() cumplirá con los requisitos, teniendo en cuenta que todos los resultados esperados ocuparán espacio en memoria.

Si lo que se necesita es realizar una operación con cada entidad y luego esa entidad no se utilizará más, el método Query.iterate() se ajusta mejor ya que permite limitar (con Query.setFetchSize() ) la cantidad de resultados que se tienen en memoria y no consumir recursos innecesariamente, haciendo que la aplicación sea más eficiente y menos propensa a fallos por falta de memoria en casos potenciales de muchos resultados en un query.


Ver También