2012-02-26 18 views
18

¡Acabo de probar mi aplicación en el generador de perfiles y descubrí que las cadenas sql usan aproximadamente el 30% de mi memoria! Esto es extrañoHibernate produce SQL diferente para cada consulta

Hay muchas cadenas de este tipo almacenadas en la memoria de la aplicación. Se trata de consultas SQL generadas por hibernación, tener en cuenta los diferentes números y guiones bajos se arrastran:

select avatardata0_.Id as Id4305_0_,...... where avatardata0_.Id=? for update 
select avatardata0_.Id as Id4347_0_,...... where avatardata0_.Id=? for update 

Aquí es la parte que no puedo entender. ¿Por qué hibernate tiene que generar diferentes cadenas sql con diferentes identificadores como "Id4305_0_" para cada consulta? ¿Por qué no puede usar una cadena de consulta para todas las consultas idénticas? ¿Es esto una especie de truco para eludir el caché de consultas?

Agradecería mucho si alguien me describiera por qué sucede y cómo evitar el desperdicio de recursos.

ACTUALIZACIÓN

Ok. Lo encontré. Me equivoqué al asumir la pérdida de memoria, fue mi culpa. Hibernate está funcionando según lo previsto.

Mi aplicación creó 121 (!) SessionFactories en 10 subprocesos, produjeron aproximadamente 2300 instancias de SingleTableEntityPersisters. Y cada SingleTableEntityPersister genera aproximadamente 15 consultas SQL con diferentes identificadores. Hibernate se vio forzado a generar aproximadamente 345,000 consultas SQL diferentes. Todo está bien, nada raro :)

+1

Podría ser útil si se pudiera proporcionar una configuración de asignación simple, el código de prueba y simple DDL tabla que reproduce esta situación. En mi experiencia, nunca he visto a Hibernate crear recuentos de índices de alias de columna tan altos. –

+0

Buen punto. Voy a tratar mañana. :) –

+0

@AndrewFrolov: Espero que mi respuesta se adapte mejor a la pregunta ahora, con sus actualizaciones. En cualquier caso, me alegro de que haya encontrado y solucionado el problema. – ManuPK

Respuesta

1

Existe una lógica detrás de la cadena de consulta que hibernate genera. Su objetivo principal es obtener alias únicos para los nombres de tablas y columnas.

De la consulta,

select avatardata0_.Id as Id4305_0_,...... where avatardata0_.Id=?

avatardata0_ ==>avatardata es el alias de la tabla y 0_ se adjunta para indicar que es la primera tabla en la consulta. Entonces, si fuera la segunda tabla (o entidad) en la consulta, debería haberse mostrado como avatardata1_. Utiliza la misma lógica para los alias de columna.

De esta manera, se evitan todos los posibles conflictos.

Estás viendo estas consultas porque has activado el show_sql marca la configuración. Esto está destinado a la depuración de consultas. Una vez que la aplicación comenzó a funcionar, se supone que debes apagarla.

Más información en los docs de API here.

No conozco muy bien la parte de consumo de memoria, pero repite las pruebas con la bandera anterior desactivada y verifica si hay alguna mejora.

+1

show_sql está desactivado. No estoy hablando de registro, estoy hablando de memoria. Veo estas consultas en el generador de perfiles, en la memoria de la aplicación, probablemente en la caché de hibernación interna. Entiendo por qué hibernate crea un alias para cada columna en un conjunto resultante. No entiendo por qué hibernate no puede reutilizar declaraciones generadas para la próxima consulta. –

+0

Entendido. He respondido sobre la parte ** ¿por qué los nombres largos? ¡Incluso no estoy seguro acerca de la solución! – ManuPK

+0

¿Tiene alguna documentación que explique por qué * hacen esto? A veces puede causar problemas de rendimiento ... http://stackoverflow.com/a/15257317/32453 – rogerdpack

1

Suponiendo que está utilizando el servidor sql, es posible que desee comprobar la declaración del tipo de parámetro para '?', Asegurándose de que la declaración dé como resultado siempre la misma declaración de longitud fija.

Los parámetros de longitud dinámica darían lugar a planes de ejecución separados para cada consulta. Esto posiblemente podría consumir muchos recursos.Lo que vemos como el mismo procedimiento, es interpretado por el servidor sql como una consulta diferente, representando un plan de ejecución por separado.

Por lo tanto,

exec myprocedure @p1 varchar(3)='foo' 

y

exec myprocedure @p1 varchar(6)='foobar' 

daría lugar a diferentes planes. Simplemente por el hecho de que las declaraciones de @ p1 difieren en tamaño.

Hay mucho que aprender sobre este comportamiento. Si lo anterior se aplica a usted, le recomendaría que lea sobre 'detección de parámetros'.

-1

No ... puede generar una consulta común dentro de la hibernación. La lógica detrás es mapear con tabla y obtener el registro desde allí. Se utiliza consulta común para toda la base de datos. Por favor, cree una consulta común así:

Ejemplo:

select t.Id as Id4305_0_,...... from t where t.Id=? 
Cuestiones relacionadas