tips data java performance hibernate orm

java - data - hibernate statistics



Problema habitual de rendimiento de hibernaciĆ³n (7)

Como ya mencionaron los chicos, el rendimiento de Hibernate tiene que ver con la configuración correcta. Una vez pude mejorar la velocidad de actualización de caché de credenciales en un factor de 10 (de 2 a 200 ms) al cambiar a una sesión sin estado (ese código en particular no dependía de ningún tipo de recuperación lenta para poder hacer lo que hice) .

Acabamos de terminar de perfilar nuestra aplicación. (ella comienza a ser lenta). el problema parece ser "en hibernación".

Es un mapeo de legado. Quién trabaja, y hazlo es trabajo. El shema relacional detrás está bien también.

Pero algunas solicitudes son lentas como el infierno.

Por lo tanto, apreciaríamos cualquier comentario sobre el error común y habitual cometido con hibernación que termina con una respuesta lenta.

Ejemplo: Ansioso en lugar de Lazy puede cambiar dramáticamente el tiempo de respuesta ...

Editar: como de costumbre, leer el manual suele ser una buena idea. Un capítulo entero cubre este tema aquí:

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html


Una de las trampas más comunes es el infame n + 1 problema de selección . Por defecto, Hibernate no carga datos que no solicitó. Esto reduce el consumo de memoria pero lo expone al problema n + 1 selecciona que puede evitarse al cambiar a la estrategia de búsqueda correcta para recuperar todos los datos que necesita para cargar objetos en su estado inicializado apropiadamente.

Pero tampoco busque demasiado o se encontrará con el problema opuesto, el problema del producto cartesiano : en lugar de ejecutar muchas instrucciones SQL, puede terminar creando declaraciones que recuperen demasiados datos.

Ese es el objetivo de la sintonía: encontrar el medio entre los datos insuficientes y demasiados para cada caso de uso de la aplicación (o al menos, para el que se debe ajustar).

Mis recomendaciones:

  • primero active el registro de SQL al nivel de Hibernate
  • ejecutar los casos de uso crítico (el 20% usa el 80% del tiempo) o incluso todos si tiene ese lujo
  • identifique consultas sospechosas y optimice el plan de búsqueda, verifique si los índices se usan apropiadamente, etc.
  • involucre a su DBA

Una cosa que sucedió en mi compañía me viene a la mente. Se puede ver si cargar una entidad también carga alguna entidad serialized , que se deserializará cada vez que se cargue la entidad. Además, al comprometer la transacción hibernate podría hacer un flush() para usted (es configurable). Si se vacía, para mantener la persistencia, hará una comparación de la entidad comprometida y la de la base de datos. En este caso, hará una comparación en el objeto serialized , lo que lleva mucho tiempo.

Otra cosa que podría hacer es verificar si tiene alguna @Cascade({CascadeType.PERSIST, CascadeType.SAVE_UPDATE}) persistencia innecesaria, es decir, la @Cascade({CascadeType.PERSIST, CascadeType.SAVE_UPDATE}) en las columnas.

Otra cosa que podría hacer, que no está específicamente relacionada con la hibernación, es que cree view para hacer una sola consulta, en lugar de hacer muchas y muchas consultas a tablas diferentes. Eso hizo una gran diferencia para nosotros en una determinada función.


Me gustaría respaldar todo lo que dijo Pascal, y solo mencionar que una solución al "problema de recuperación de demasiados datos" es usar proyecciones de Hibernate, y buscar los datos en un DTO plano, que solo consiste en las columnas realmente necesario. Esta es específicamente una opción, cuando no está planeando actualizar los datos en esta sesión de Hibernate, por lo tanto, no necesitará objetos mapeados. Tomado de este artículo , que contiene más consejos de rendimiento de Hibernate.


El mapeo de las relaciones m: n y n: 1 es la raíz de los frecuentes problemas de rendimiento con Hibernate.

Hibernate Caching no puede ayudar mucho si está utilizando HQL, ya que Hibernate no puede traducir consultas en llamadas a caché, por lo que no puede usar caché con HQL (al menos cuando estaba leyendo su código).

Si quieres un enfoque simple, rápido y liviano, puedo recomendarte fjorm

Dislaimer: soy un fundador del proyecto fjorm


Los errores más comunes son las selecciones N + 1 que están ocultas detrás de las escenas. Por lo general, esos no se detectan antes de la producción y los perfiladores habituales no son excelentes para revelarlos.

Puede probar un generador de perfiles interactivo como XRebel: se ejecuta todo el tiempo y revela problemas durante el desarrollo, por lo que puede solucionarlos de inmediato y capacitar a los desarrolladores para que no cometan esos errores.

http://zeroturnaround.com/blog/hibernate-orm-with-xrebel-revealing-multi-query-issues-with-an-interactive-profiler/


Como otros ya han mencionado, el problema de N + 1 es el problema común en las aplicaciones de JPA. Actualmente estoy trabajando en una herramienta para la detección temprana de estos problemas en las pruebas de su unidad y en sus entornos de prueba. Se llama JDBC Sniffer , es de código abierto y completamente gratuito

Le permite controlar el número de consultas ejecutadas en sus entornos de prueba directamente en su navegador:

También proporciona extensino a los marcos de prueba de unidades populares para detectar el problema de N + 1 mientras aún se desarrolla el código mediante anotaciones:

import com.github.bedrin.jdbc.sniffer.BaseTest; import com.github.bedrin.jdbc.sniffer.Threads; import com.github.bedrin.jdbc.sniffer.Expectation; import com.github.bedrin.jdbc.sniffer.Expectations; import com.github.bedrin.jdbc.sniffer.junit.QueryCounter; import org.junit.Rule; import org.junit.Test; public class QueryCounterTest extends BaseTest { // Integrate JDBC Sniffer to your test using @Rule annotation and a QueryCounter field @Rule public final QueryCounter queryCounter = new QueryCounter(); @Test @Expectations({ @Expectation(atMost = 1, threads = Threads.CURRENT), @Expectation(atMost = 1, threads = Threads.OTHERS), }) public void testExpectations() { executeStatement(); executeStatementInOtherThread(); } }