2009-05-20 8 views
8

Actualmente estoy experimentando con EJB3 como un estudio previo para un gran proyecto en el trabajo. Una de las cosas que estoy investigando es el almacenamiento en caché de consultas.¿Por qué el almacenamiento en caché de consultas con Hibernate hace que la consulta sea diez veces más lenta?

He hecho un modelo de dominio muy simple con anotaciones JPA, una interfaz comercial @Local y una implementación @Stateless en un EJB-JAR, desplegada en un EAR junto con una aplicación web muy simple para realizar algunas pruebas básicas. El EAR se implementa en la configuración predeterminada de JBoss 5.0.1 sin modificaciones. Esto fue muy directo y funcionó como se esperaba.

Sin embargo, mi última prueba involucrados caché de consulta, y me dieron algunos resultados extraños:

  • tengo una clase de dominio que sólo se asigna un identificador y un valor de cadena, y han creado unos 10.000 filas en esa particular tabla
  • en el grano de negocio, no es una consulta muy simple, m SELECT MiClase m
  • sin caché, esto se ejecuta en aproximadamente 400 ms en promedio
  • Con caché de consultas activado (a través de consejos sobre la consulta), la la primera ejecución, por supuesto, lleva un poco más de tiempo, alrededor de 1200ms. ¡Las próximas ejecuciones toman 3500ms en promedio!

Esto me dejó perplejo, así que habilité el show_sql de Hibernate para mirar el registro. Sin memoria caché, y en la primera ejecución con caché habilitada, hay un SELECT registrado, como se esperaba. Cuando debería obtener aciertos de caché, Hibernate registra un SELECT para cada fila en la tabla de la base de datos.

Eso sin duda explicaría el lento tiempo de ejecución, pero ¿alguien puede decirme por qué sucede esto?

+0

Puede encontrar información útil en mi blog sobre el caché de consultas aquí: * http://tech.puredanger.com/2009/07/10/hibernate-query-cache/ –

Respuesta

16

La manera en que funciona la caché de consultas es que solo almacena en caché los ID de de los objetos devueltos por la consulta. Por lo tanto, su declaración SELECT inicial podría devolver todos los objetos, e Hibernate se los devolverá y recordará los ID.

La próxima vez que publique la consulta, sin embargo, Hibernate revisa la lista de ID y se da cuenta de que necesita materializar los datos reales. Entonces va a a la base de datos para obtener el resto. Y hace un SELECCIONAR por fila, que es exactamente lo que está viendo.

Ahora, antes de pensar, "esta función está obviamente rota", la razón por la que funciona de esta manera es porque Query Cache está diseñado para funcionar conjuntamente con Second Second Cache. Si los objetos se almacenan en la caché L2 después de la primera consulta, Hibernate buscará allí para satisfacer las solicitudes por ID.

Le recomiendo que levante el libro Java Persistence with Hibernate para aprender más sobre esto. El Capítulo 13 en particular cubre la optimización de consultas y cómo usar la memoria caché de manera efectiva.

+1

Genial, intentaré habilitar el Caché de segundo nivel también Me encanta este lugar :-) –

+0

Este libro tiene un par de años, ¿todavía está actualizado? –

+0

Buena pregunta, Nathan. Estoy usando Hibernate 3.2, y todo parece completamente actualizado para mí. El libro también cubre todas las anotaciones de JPA 1.0, e incluye una introducción a JBoss Seam. ¿Hay alguna característica nueva importante en Hibernate 3.3 que podría no estar cubierta? –

Cuestiones relacionadas