JPA masivo

WTH.

Tengo una aplicacion JEE estoy utilizando JPA, para ir al grano estoy utilizando un Entity manager y dentro de una sola transaccion creo y persisto muchas [minimo mas de 10k] entidades las cuales despues de persistirlas las desreferencio esperando que el Garbage Collector las destruya ¬¬..

estoy haciendo consultas, por cada entidad que créo pregunto si ya fue creada esa llave primaria, y si no ha sido creada entonces se persiste, si ya fue creada solo la consulta...

El problema que tengo es que según va creciendo el número de entidades que persisto el proceso se va haciendo mas lento. Las primeras entidades siempre son rapidas pero para la entidad 100 el proceso es mas lento y si el proceso continua se va haciendo mas lento cada vez...

estoy dando flush cada 3k entidades persistidas, al inicio tiene intervalos de 1minuto cada 3k entidades, va en la entidad 130k y tiene intervalos de 30 min cada 3k :S

si creen que es necesaría más info nomas pregunten ^^.

Muchas gracias por cualquier ayuda que me puedan dar.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Utiliza un profiler ( como

Utiliza un profiler ( como Visual VM ) e investiga donde se está llendo toda esa memoria.

Imagen de neko069

Pues... a mi me suena más a

Pues... a mi me suena más a que estás haciendo tareas manuales que ya estarían automatizadas por JPA ....yo en lo particular te entendería más si pusieras algo de código ( entre tags de < code> y < / code> por favor )
A su vez, también me suena a que no tienes un pool de conexiones, tienes uno? puedes mostrar tu archivo de configuración de tu persistence.xml ??

Bueno

A mi tambien me suena más a que soy noob :P
de codigo nel,
y no, no tengo pool de conexiones, pero solo estoy haciendo uso de una sola conexion, no creo que sea necesario o si?

Imagen de neko069

!!

Estás usando una sola conexión?? cómo es eso?? sólo inicias una conexión y haces todo el relajo que explicaste en el post inicial?
Bueno, en todo caso, te recomendaría que te configuraras un pool de conexiones, como C3PO, para que te administre las conexiones a la base de datos...

Pues en estricta teoría no,

Pues en estricta teoría no, si solo tienes un cliente ( aunque eso de estar abriendo y cerrando conexiones no esta padre ), pero cuando tengas dos vas a tener más problemas.

server vs server

amm :S, mi servidor weblogic es el unico que se conecta a la Base de Datos ¬¬, no se me hace raro [por que a ustedes si :S], y para este proceso es el unico que se conectará de esta manera y persistirá mucha información.

Imagen de neko069

Pues yo creo que tú tienes el

Pues yo creo que tú tienes el entendido de que usas una sola conexión, pero igual se están generando muchas, y pues si no hay nada que las gestione, te puede causar problemas en tus transacciones....te dejo el link del c3po, checa la documentación, lo puedes configurar y ver la diferencia de tiempos aquí

Imagen de ezamudio

manejo de conexiones

neko069 tiene razón... de entrada el problema suena como que no requiere un pool porque es una sola tarea realizando todo, pero... si está usando JPA y son muchas tareas que no están dentro de una transacción, el motor de JPA que usa podría estar abriendo y cerrando conexiones, por lo que un pool sí convendría, aunque fuera un pool de 1 o 2 conexiones, para reusar la misma siempre. Pero si tienen Weblogic casi seguro ya trae un pool de conexiones.

Yo no veo que menciones problemas de memoria, sino de lentitud. Mencionas que llamas al GC cada 3mil inserts pero eso supongo que es preventivo, o tal vez te quedabas sin memoria antes y se lo agregaste. Pero la cosa es que ahora está lento. Lo interesante sería saber: si antes te quedabas sin memoria y por eso pusiste el GC, a los cuántos inserts te quedabas sin memoria? y qué tal funcionaba en cuanto a la velocidad? Tal vez era más rápido y ahora se tarda, o tal vez de todas formas era lento (eso te diría de manera muy sencilla si el GC es lo que hace que se tarde la app, aunque no creo porque mencionas también que a los 100 objetos ya se nota que se tarda).

No tendrás por ahí un loop interno que se ejecuta tantas veces como el índice del objeto que vas a insertar? O sea que iteras por una lista de miles de objetos y para el primero, hay un ciclo interno que se ejecuta una vez, para el segundo ese ciclo interno se ejecuta dos veces, para el tercero tres veces, etc y por eso para el centésimo objeto el ciclo se ejecuta 100 veces y pues ya se nota y para el objeto 3000 el ciclo se ejecuta 3000 veces, etc.

RESPUESTAS

Lo interesante sería saber: si antes te quedabas sin memoria y por eso pusiste el GC, a los cuántos inserts te quedabas sin memoria?

Bueno desde el principio nunk pense en mantener las entidades en memoria [referenciadas] por que no me seria util, a menos que las creara y posteriormente las persistiera todas juntas [lo cual debí hacer desde un principio -.- pero opte por esta forma por que tenía que consultarlas si ya se habían creado :S], por esto nunk las retube en alguna referencia (aunque nunk mande llamar especificamente al GC me refería a que esperaría a que las destrullera).

Mencionas que llamas al GC cada 3mil inserts
lo que mando llamar es el flush() no el GC.

seguire checando si no tengo un ciclo locochon por alli ..

thx

Imagen de ezamudio

flush()

Entonces tienes una sesión abierta todo este tiempo? Si tienes una sesión abierta todo el tiempo, seguro estás usando la misma conexión a base de datos y por lo tanto todo lo que hemos dicho del pool de conexiones no aplica. Pero tal vez, la sesión se satura demasiado de información, y te convendría no solamente hacerle flush, sino cerrarla y abrir una nueva (a menos que eso te vaya a dar broncas con las entidades que ya creaste, pero según entiendo, no debe ser así).

Definiste un cache para la entidad que estás usando? tengo entendido que es una sola entidad con la que estás trabajando (o sea, una clase, mapeada a una tabla en la base de datos, eso es una entidad. Los objetos que creas para insertar ahí son instancias, no entidades). Tal vez hay definido un cache para esa entidad y por eso entre más insertas, más se tarda...

=O ::mastaa::

=O ::mastaa::
pues buen tip el de la entidad, y estoy usando 3 entidades, pero me suena muy buena idea lo de cerrar la transaccion y abrir otra, dejame ver si funcionaba, espero que si, se oye bastante viable.

Aunque tardare un rato, gracias por lo pronto.

Spartans, Wts Ur Profesion?!

Si brother ya se arreglo, muchas gracias.

Aunque me quedo con la espina clavada, me gustaría saber que es lo que estaba haciendo.

Lo unico que hice fue que cada 3k instancias persistidas en ves de darle flush cierro la transacción y abro una nueva. Ahora duran todas el mismo intervalo de tiempo, pero si hubiera sido un ciclo, el ciclo se seguiría haciendo ya que no modifique nada más, estan de acuerdo?

Ps quien sabe como stubo el rollo. Si a alguien se le ocurre algo rápido pues estaría bien para aprender algo de teoría ^^.

Otra cosa, si no pongo un pool de conexiones se me armará un rollo? por que por lo pronto no tengo pero no he hecho pruebas de performance.

Imagen de neko069

Lo que pasa es que un pool de

Lo que pasa es que un pool de conexiones te gestiona/maneja/administra precisamente ( valga la rebuznancia ) las conexiones a la base de datos, entonces, si estas resolviendo que vas a usar transacciones, pues vas a manejar varias conexiones, porque una sola transacción que haga todo tu relajito, sería el mismo problema que dejarle todo a la sesión, aunque fuera un solo cliente, te recomiendo un pool, con unas 10 conexiones, para que no te preocupes, ya si necesitas más con el tiempo, pues sólo configuras las conexiones... eso no quita que tengas que hacer flush() cada X inserts que estés ejecutando...

¿Entiendo entonces que se

¿Entiendo entonces que se quedaba todo en memoria como para hacerle un rollback o algo así?

Imagen de ezamudio

sesión

El problema era con la sesión de JPA. La sesión está asociada a una conexión, por lo que no había broncas de conexiones, no era por ahí el problema. Pero una sesión abierta lleva un registro de lo que ha leído y de lo que ha insertado, hasta que se cierra (creo que hay otro método para que se olvide de todo lo que tenía pero no es  ).

Conforme se iban insertando más objetos, la sesión tiene más info en memoria. Aunque las referencias en el código de White_King se apunten a null, al GC no se lleva esos objetos porque la sesión sigue haciendo referencia a ellos, además de que tiene mapas y cosas así que van creciendo conforme se insertan más datos.

Al cambiar su código para que en vez de hacer flush, se cierre la sesión y se inicie una nueva, pues todas las sesiones guardan más o menos la misma cantidad de información, por lo que el tiempo ahora ya es constante.

Por esto es que JPA no es la mejor opción para insertar grandes volúmenes de datos. Mejor usar JDBC ya sea pelón, o de preferencia con algo como Spring JDBC.

Imagen de ezamudio

Transaccionalidad

La única bronca sería si se debe manejar transaccionalidad, es decir, si se tienen que insertar todos los datos o ninguno; en caso que un INSERT falle, darle rollback a todo; en ese caso se debe manejar todo en la misma transacción (aunque creo, CREO, que sí podría hacerse lo mismo de cerrar y abrir distintas sesiones, pero creo que todas se quedan abiertas hasta que se haga el commit o rollback).

Pues me parece bastante

Pues me parece bastante Logico lo que mencionas ezamudio, mil gracias por el apoyo chavos, aqui andamos.

haber si me agregan chessmastersport@hotmail.com

Imagen de CybJer

Interesante

Entonces sucederia lo mismo si intentara guardar una larga lista de objetos con Hibernate? (Tambien en una transaccion) @ezamudio

Imagen de ezamudio

Hibernate y JPA en general no son la mejor opción para manejar grandes volúmenes de datos, ni en consultas ni en inserción. Son buenos para poder traer algunos datos de una base SQL y manejarlos como objetos, lo cual facilita mucho su edición, y también para transacciones muy puntuales (con pocos objetos, donde se va a afectar un saldo por ejemplo y registrar un movimiento y dos o tres cosas más). Pero para insertar lotes de miles de datos, mejor usar JDBC directamente (o a través de Spring JDBC). Igual para reportes o barrido de grandes volúmenes de datos.

Imagen de ezamudio

mejor opción

Otra cosa que pueden probar cuando hacen inserción masiva de datos en Hibernate (y seguramente en JPA en general, no sé qué implementación usa White_King), es algo como esto. Suena a que es exactamente el mismo problema. Resulta que no es suficiente session.flush(), también hay que hacer session.clear(), y con eso se puede seguir usando la misma sesión, y todo puede ir en una sola transacción.

Imagen de neko069

Por eso decía que mostrara

Por eso decía que mostrara algo de código, igual y con el tip de @ezamudio hubiera bajado el tiempo entre inserciones aún con la misma sesión... lo bueno que (aparentemente) ya quedó..

Imagen de CuicaJavier

Ezamudio!!

@ezamudio sigue siendo Hibernate y JPA malos para manejar grandes volúmenes de datos? Estoy por crear una aplicacion con Swing y pienso usar JPA, uno de los requisitos indispensables es que al día los diferentes usuarios van a registrar miles de datos.

Imagen de ezamudio

Para inserción masiva lo mejor es JDBC directo.

Por "inserción masiva" me refiero a realizar miles de inserts a una base de datos, uno tras otro, como un solo lote de datos, sin intervención del usuario una vez que el proceso inicia. Si un usuario va a insertar miles de datos durante el día porque le da click a un botón cada 15 segundos durante 10 horas seguidas, eso no es inserción masiva de datos.