2010-04-22 17 views
7

Tengo 5 tablas MySQL InnoDB: Test,InputInvoice,InputLine,OutputInvoice,OutputLine y cada una está mapeada y funciona en Hibernate. He jugado con el uso de StatelessSession/Session y el tamaño de lote JDBC. He eliminado todas las clases de generador para permitir que MySQL maneje la generación de id, pero todavía está funcionando bastante lento. Cada una de esas tablas está representada en una clase java, y asignadas en hibernación en consecuencia. Actualmente, cuando llega el momento de escribir los datos, recorro los objetos y hago un session.save(Object) o session.insert(Object) si estoy usando StatelessSession. También hago una descarga y limpieza (cuando uso la sesión) cuando mi conteo de líneas alcanza el tamaño máximo de lote jdbc (50).Mapeo de relaciones Hibernate/Insertos por lotes acelerados

  1. ¿Sería más rápido si tuviera esto en una clase 'padre' que contenía los objetos e hizo un session.save(master) en lugar de cada uno de ellos?
  2. Si los tuviera en una clase maestra/contenedor, ¿cómo mapearía eso en hibernación para reflejar la relación? La clase contenedor no sería una tabla propia, sino una relación basada en dos índices run_id (int) y line (int).
  3. Otra dirección sería: ¿Cómo puedo obtener Hibernate para hacer una inserción de varias filas?
+0

me olvidó mencionar que cada una de esas mesas tiene muchas columnas – ashurexm

Respuesta

7

La solución final para mí fue usar la respuesta de voetsjoeba como punto de partida. Mi configuración de hibernación utiliza las siguientes opciones:

hibernate.order_inserts = true 
hibernate.order_updates = true 
  • he cambiado el uso de Session a StatelessSession

  • reordenado el código Java para procesar todos los elementos en un lote de una mesa a la vez Así que todo de la tabla x, entonces la mesa Y, etc.

  • retira el <generator> de cada clase . Java ahora lo crea y lo asigna al objeto

  • Creado lógica que me permitió determinar si se estaba estableciendo simplemente un id y no escribo líneas 'vacíos' de la base de datos

  • Finalmente, encendido dynamic-insert para mis clases en su hibernación las definiciones de este modo: <class name="com.my.class" table="MY_TABLE" dynamic-insert="true">

14

La estrategia de generación de ID es crítica para la inserción de lotes en Hibernate. En particular, la generación de IDENTIDAD normalmente será no (tenga en cuenta que AUTO también se asigna a IDENTIDAD). Esto se debe a que, durante la inserción del lote, Hibernate tiene un indicador llamado "requiresImmediateIdAccess" que indica si los identificadores generados se requieren o no inmediatamente; si es así, el procesamiento por lotes está deshabilitado.

Puede detectarlo fácilmente en los registros de nivel de DEPURACIÓN cuando dice "ejecutar la inserción de identidad inmediatamente": esto significa que se ha omitido el procesamiento por lotes porque se indicó que los ID generados son necesarios inmediatamente después de la inserción.

Estrategias de generación que normalmente hacen funcionan como TABLE y SEQUENCE, porque Hibernate puede pregenerar los ID, lo que permite la inserción de lotes.

Una forma rápida de detectar si su inserción por lotes funciona es activar registros de nivel DEBUG porque BatchingBatcher le dirá explícitamente el tamaño de lote que está ejecutando ("Ejecución de tamaño de lote:" + tamaño de lote).

Además, las siguientes propiedades son importantes para lograr la inserción de lotes. Me atrevo a decir que son necesarios ya que no soy lo suficientemente hibernación de un experto para hacerlo - tal vez es sólo mi configuración particular - pero en mi experiencia, sin embargo, se les necesitaba:

hibernate.order_inserts = true 
hibernate.order_updates = true 

Estas propiedades son bastante pobremente documentado, pero creo que lo que hicieron fue permitir que las sentencias SQL INSERT y UPDATE se agruparan adecuadamente para la ejecución por lotes; Creo que estas podrían ser las inserciones de varias hileras que buscas. No me disparen si estoy equivocado en esto, estoy recordando de memoria.

También voy a seguir adelante y supongo que establece la siguiente propiedad; de lo contrario, esto debería servir como recordatorio:

hibernate.jdbc.batch_size = xx 

Donde xx es el tamaño de lote deseado, naturalmente.

+0

@JDR: Muchas gracias por toda esta información. Estoy en el proceso de cambiar mi generación de ID a original (¿esto también deshabilitará el procesamiento por lotes?) Y añadiré sus otras ideas. Ya tengo jdbc.batch_size = 50 pero no tengo order_inserts/updates. Te dejaré saber qué tan bien funciona. – ashurexm

+0

@JDR: Implementé sus sugerencias y puedo ver que está agrupando mis inserciones para que todas las tablas se inserten en orden. Está insertando TODA la prueba, luego TODO, etc. Me está mostrando que el tamaño del lote es 50, lo cual es bueno. Pero sigo obteniendo aproximadamente el mismo rendimiento que antes, que es de aproximadamente 5 minutos para 3300 registros (tenga en cuenta que cada registro significa una inserción en 5 tablas diferentes). – ashurexm

+1

@manyxcxi: Cambiando los identificadores a lote nativo desactivado para mí debido a la variable requiresImmediateIdAccess (usando H2 e Hibernate 3.5.1-Final). Si el dosificador dice que está realizando lotes de 50, entonces eso es más o menos lo que está haciendo, esta es la meta aquí. Cinco minutos para 3300 registros parece un poco excesivo, puedo insertar 1000 registros en aproximadamente un segundo incluso con algunos gastos generales adicionales de Hibernate Search (aunque en una base de datos H2 incrustada). ¿Tiene algunos registros de salida de muestra en cualquier lugar que pueda ver? ¿Qué base de datos está ejecutando y qué grupo de conexiones está utilizando? – voetsjoeba

Cuestiones relacionadas