2010-02-20 20 views
5

Tengo problemas para que Hibernate realice una inserción masiva en MySQL.Hibernate/MySQL Problema de inserción masiva

estoy usando Hibernate 3.3 y MySQL 5.1

En un nivel alto, esto es lo que está pasando:

@Transactional 
public Set<Long> doUpdate(Project project, IRepository externalSource) { 
    List<IEntity> entities = externalSource.loadEntites(); 
    buildEntities(entities, project); 
    persistEntities(project); 
} 
public void persistEntities(Project project) { 
    projectDAO.update(project); 
} 

Esto da lugar a entradas de registro n (1 por cada fila) de la siguiente manera:

Hibernate: (??????,,,,,) insertar en ProjectEntity (nombre, parent_id, camino, project_id, estado, tipo) valores

Me gustaría ver que esto se realice por lotes, por lo que la actualización es más efectiva. Es posible que esta rutina genere decenas de miles de filas, y un viaje de db por fila es un asesino.

¿Por qué no se consigue esto por lotes? (Tengo entendido que se supone que las inserciones por lotes deben ser predeterminadas, cuando corresponda, por hibernación).

Respuesta

5

tal como se documenta en el Chapter 13. Batch processing:

Si está llevando a cabo por lotes procesamiento tendrá que permitir el uso de JDBC procesamiento por lotes. Esto es absolutamente esencial si desea lograr un rendimiento óptimo. Ajuste el tamaño de lote JDBC a un número razonable (10-50, por ejemplo):

hibernate.jdbc.batch_size 20 

Hibernate deshabilita dosificación inserción en el nivel JDBC transparente si utiliza un generador de identificador de identidad.

No se olvide de flush y luego clear la sesión regular o te OutOfMemoryException como se documenta en 13.1. Batch inserts.

Pero IMO, para decenas de miles de filas, debe considerar usar the StatelessSession interface.

+0

¿Esto permitirá el procesamiento por lotes de instrucciones SQL? (Si las sesiones mantienen sonidos de estado en lugar de batching ortogonales, pero tal vez infiero demasiado del nombre de la clase) – meriton

+0

@meriton He actualizado mi respuesta para agregar más detalles. –

+0

+1: ¡Ahora lo entiendo, gracias! – meriton

0

Pascal lo ha prácticamente clavado en el contexto de hibernación. Como alternativa, puede usar Batchsqlupdate de la plantilla de jbdc. Sin embargo, tengo que advertirle que las instancias de hibernación en caché pueden no reflejar los cambios realizados utilizando lo anterior. En nuestro proyecto, tuvimos que tomar medidas de precaución para superar esto, creando un cronograma diferente (otro problema creado, pero bajo nuestro control)

7

La respuesta de Pascal es correcta. Sin embargo, como está utilizando MySQL, también le recomiendo que intente utilizar el parámetro rewriteBatchedStatements=true en su URL JDBC.

Este parámetro hace que el controlador JDBC vuelva a escribir dinámicamente sus lotes INSERT para usar un solo INSERT "multivaluado", p.:

INSERT INTO mytable (mycol) VALUES (0); 
INSERT INTO mytable (mycol) VALUES (1); 
INSERT INTO mytable (mycol) VALUES (2); 

se re-escrito a:

INSERT INTO mytable (mycol) VALUES (0), VALUES (1), VALUES (2); 

Esto puede hacer una diferencia significativa en algunos casos. Ver http://www.jroller.com/mmatthews/entry/speeding_up_batch_inserts_for para algunas medidas de ejemplo.

Cuestiones relacionadas