java - tablas - Mapeo de relaciones de Hibernate/Acelerar inserciones de lotes
programacion hibernate java (2)
Tengo 5 tablas MySQL InnoDB: Test,InputInvoice,InputLine,OutputInvoice,OutputLine
y cada una está mapeada y funcionando 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 se representa en una clase Java, y se mapea en hibernación en consecuencia. Actualmente, cuando llega el momento de escribir los datos, recorro los objetos y hago una 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 de lote máximo de jdbc (50).
- ¿Sería más rápido si tuviera estos en una clase ''padre'' que tuviera los objetos e hiciera una
session.save(master)
lugar de cada uno? - 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).
- Otra dirección sería: ¿Cómo puedo obtener Hibernate para hacer una inserción de varias filas?
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 generalmente no funcionará (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.
Las estrategias de generación que normalmente funcionan son TABLE y SEQUENCE, porque Hibernate puede pregenerar los ID, lo que permite la inserción de lotes.
Una manera rápida de detectar si su inserción por lotes funciona es activar los registros de nivel de DEPURACIÓN, ya que BatchingBatcher le dirá explícitamente el tamaño del lote que está ejecutando ("Ejecución del tamaño de lote:" + tamaño de lote).
Además, las siguientes propiedades son importantes para lograr la inserción de lotes. No me atrevo a decir que sean necesarios ya que no soy lo suficientemente experto en Hibernate como para hacerlo, tal vez sea solo mi configuración particular, pero en mi experiencia fueron necesarios, no obstante:
hibernate.order_inserts = true
hibernate.order_updates = true
Estas propiedades están bastante poco documentadas, 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 seguiré adelante y asumiré que estableces la siguiente propiedad; si no, esto debería servir como recordatorio:
hibernate.jdbc.batch_size = xx
Donde xx es el tamaño de lote deseado, naturalmente.
La solución final para mí fue usar la respuesta de voetsjoeba como punto de partida. Mi configuración de hibernación usa las siguientes opciones:
hibernate.order_inserts = true
hibernate.order_updates = true
Cambié de usar
Session
aStatelessSession
Re-ordenó el código de Java para procesar todos los elementos en un lote una tabla a la vez. Así que toda la tabla x, luego la tabla y, etc.
Se eliminó el
<generator>
de cada clase. Java ahora lo crea y lo asigna al objetoCreación de lógica que me permitió determinar si solo se estaba configurando una identificación y no escribir líneas ''vacías'' en la base de datos
Finalmente,
<class name="com.my.class" table="MY_TABLE" dynamic-insert="true">
dynamic-insert
para mis clases en sus definiciones de hibernación, como por ejemplo:<class name="com.my.class" table="MY_TABLE" dynamic-insert="true">