Eficiencia Ejecutando Querys Con Hibernate
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 en nuestras
aplicaciones.
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 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.
Vea También
http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Query.html Hibernate Query Interface http://www.hibernate.org/hib_docs/reference/en/html/objectstate-querying.html Hibernate Queriying http://static.springframework.org/spring/docs/1.1.5/api/org/springframework/orm/hibernate/HibernateTemplate.html Querys con Spring HibernateTemplate http://articles.techrepublic.com.com/5100-10878_11-1046675.html Deciding between iterators and lists for returned values in Java http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html Interface java.sql.ResultSet