Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Conexión con bases de datos (https://www.clubdelphi.com/foros/forumdisplay.php?f=2)
-   -   Insertar 450,000 de un golpe. (https://www.clubdelphi.com/foros/showthread.php?t=70496)

acalderonr 24-10-2010 23:07:40

Insertar 450,000 de un golpe.
 
Hola a todos. He buscado algo que me oriente en los foros y no encuentro exactamente lo que me gustaría hacer.

Estoy haciendo una aplicación para administración de Vales, pero de cada vale necesito ciertos campos y un registro independiente vale por vale, por tanto, mi cliente recibe de entrada 450,000 vales en diferentes denominaciones, pero necesito, por tanto, agregar un registro por cada folio de vale.

Estoy usando Delphi 6, Firebird 2.1 con los componentes de la pestaña Interbase en mi máquina Core2Duo, si ejecuto un for ... while del 1 al 450mil con un IBQuery con la sentencia "insert into almacen ..." para cada vale, se tarda 52segundos en hacerlo, alguien tendrá una idea para hacerlo mas eficiente?

Espero haber sido claro. Gracias de antemano y saludos.

ASAPLTDA 25-10-2010 01:45:12

Mejora rendimiento
 
Verifica si puedes deshabilitar indices, triggers, efectua commit cada 10.000 registros, mientras las insercion masiva

AzidRain 25-10-2010 01:50:35

aun asi 45 segundos para casi medio millon de registros me parece bastante aceptable.

acalderonr 25-10-2010 02:05:59

En efecto, es bastante razonable el tiempo.
 
Gracias ASAPLTDA por tu respuesta. De hecho no tengo habilitado ningún Trigger ni Índice ni nada, solo es que a veces los usuarios son bastante desesperados. Pero me tocará hacerlos entrar en razón :).

En efecto AzidRain, es bastante razonable 52 segundos. Lo voy a probar con un Procedure del lado del servidor y veré si mejora un poquito.

Gracias por contestar. Saludos.

ASAPLTDA 25-10-2010 16:24:49

masivo
 
lo otro que puedes hacer es generar una carga de registro pero particionada el proceso 1 graba 99.9999 registros el proceso 2 graba 100.000 a 199.000 eso generaria una carga simultanea a a base de datos es posible que mejore . Otra solucion :D es us disco mas rapido ahora en el mercado hay unod discos superveloces pero +$$$$:eek:

Kipow 25-10-2010 16:47:12

Cita:

Empezado por ASAPLTDA (Mensaje 380331)
lo otro que puedes hacer es generar una carga de registro pero particionada el proceso 1 graba 99.9999 registros el proceso 2 graba 100.000 a 199.000 eso generaria una carga simultanea a a base de datos es posible que mejore . Otra solucion :D es us disco mas rapido ahora en el mercado hay unod discos superveloces pero +$$$$:eek:

Como dice aca el compañero podrias dividir la carga en 10 partes iguales para poder mostrarles el progreso de la carga de datos asi la desesperacion es menor jaja te lo digo por experiencia.

Ahora para mejorar la velocidad pues verifica que tus indices sean numeros enteros (al menos la primaria) eso agilizara un poco la carga.

duilioisola 25-10-2010 17:59:18

Prueba cual es la diferencia de velocidad entre estas dos opciones:
- generando el SQL directamente
- generando un SQL con parámetros y luego ir rellenando los parámetros.

Código Delphi [-]
with IBQuery do
begin
   {Abrir transaccion y demas requerimientos}
   while hay_registros_para procesar do
   begin
      SQL.Text := 'insert into almacen (campo1, campo2, ...) values ('+param1+','+param2+','...+')';
      ExecQuery;
   end
   Commit;
end

Código Delphi [-]
with IBQuery do
begin
   {Abrir transaccion y demas requerimientos}
   SQL.Text := 'insert into almacen (campo1, campo2, ...) values (?param1,?param2,...)';
   while hay_registros_para procesar do
   begin
      Params.ByName['Param1'].AsString := parametro1;
      Params.ByName['Param2'].AsString := parametro2;
      ExecQuery;
   end
   Commit;
end

mightydragonlor 25-10-2010 19:48:33

Hazlo por procedimiento almacenado, mejora notablemente ya que solo viajan los datos y no la instrucción por el cable, ademas, el servidor siempre ejecuta mas rápido un procedimiento almacenado.

ASAPLTDA 25-10-2010 20:55:51

Ampliacion Concepto
 
[quote=Kipow;380335]Como dice aca el compañero podrias dividir la carga en 10 partes iguales para poder mostrarles el progreso de la carga de datos asi la desesperacion es menor jaja te lo digo por experiencia.

la idea es generar multiples hilos de carga de datos si requieren intervencion del operador, o si es como entiendo usas un procedimiento almacenedo para recibir la cabecera de los volantes y en la base de datos generas los detalles

Kipow 25-10-2010 23:21:55

[quote=ASAPLTDA;380365]
Cita:

Empezado por Kipow (Mensaje 380335)
Como dice aca el compañero podrias dividir la carga en 10 partes iguales para poder mostrarles el progreso de la carga de datos asi la desesperacion es menor jaja te lo digo por experiencia.

la idea es generar multiples hilos de carga de datos si requieren intervencion del operador, o si es como entiendo usas un procedimiento almacenedo para recibir la cabecera de los volantes y en la base de datos generas los detalles

Con diferentes hilos podria mejorar bastante, no es para nada mala idea. yo decia lo de la division para poder mostrar el progreso, pero me parece mejor eleccion la de multiples hilos (igual dependera del servidor de BD)

duilioisola 25-10-2010 23:47:31

1 Archivos Adjunto(s)
He hecho esta prueba y definitivamente conviene hacer un SQL con parámetros.
Lo que no fue concluyente es si es preferible hacer un insert o ejecutar un procedimiento para insertar.
Todo me daba el mismo tiempo.
Pruébalo en tu servodor a ver como va.
(Hecho en Delphi 6, pero con componentes standard, para que no tengas problemas)

AzidRain 27-10-2010 15:52:24

Otra solución simple pero que los usuarios entienden es poner justo antes de lanzar la consulta un msgbox: "Esta consulta tardará unos segundos...espere por favor...leyendo >500,000 registros" un poco bizarro pero increiblemente funciona

Al González 27-10-2010 19:31:35

Off topic
 
Cita:

Empezado por AzidRain (Mensaje 380587)
[...] un poco bizarro pero increiblemente funciona

¿Solución valiente, generosa, lucida o espléndida? ;)

Delfino 28-10-2010 21:53:26

Cita:

Empezado por duilioisola (Mensaje 380397)
Lo que no fue concluyente es si es preferible hacer un insert o ejecutar un procedimiento para insertar.
Todo me daba el mismo tiempo.

Sin lugar a dudas el procedimiento almacenado es mas rapido y eficiente. No dudes en usarlo..
Tambien te conviene actualizar a la ultima version de Firebird, hay cierta mejoria en la rapidez en algunas circunstancias..

AzidRain 29-10-2010 01:17:25

Mi estimado Al, yo solo diría "Solución que le sirve para el usuario final" y punto. Como siempre he defendido al usuario el vale leches que si el sql, que si la consulta, que si no está optimizada, etc. Quieren cosas que ellos entiendan en su propio lenguaje y con eso están conformes. ¿Que si un proceso tarde 1 minuto? se paran por un café y san seacabó, lo que les molesta es la incertidumbre de no saber que pasa con el programa.

mamcx 29-10-2010 04:31:37

Es *absolutamente* necesario que el usuario espere????


Porque de lo contrario, yo diria que es mejor poner el proceso en un thread en el background y notificar cuando haya terminado (tipo notificacion de messenger).

Muchas veces la desesperacion es mas porque el programa esta colgado, a que el proceso en si se demore...

--------

No olvides mirar las recomendaciones que da la documentacion de la BD:

http://www.firebirdfaq.org/faq209/

O quizas:

http://www.firebirdfaq.org/faq336/

---------
He usado http://www.da-soft.com/anydac/ y en mi experiencia con este driver (de pago) es que tiene un excelente desempeño. Mucho mejor que lo que viene de "fabrica" en Delphi

Al González 29-10-2010 06:04:37

Aclaración del off topic
 
Cita:

Empezado por AzidRain (Mensaje 380790)
Mi estimado Al, yo solo diría "Solución que le sirve para el usuario final" y punto. Como siempre he defendido al usuario [...]

Perdón, creo que se entendió mal mi off topic. Me parece adecuado el consejo que diste y voy de acuerdo con tu punto de vista sobre los usuarios y demás. :)

Es que me llamó la atención lo de bizarro, cuyo significado puse a manera de juego. Te ofrezco una disculpa por el mal entendido. :o

AzidRain 29-10-2010 16:30:42

No te preocupes mi estimado Al, aqui no pasa nada nadie se molesta. Jajaja. Por otro lado estaremos de acuerdo que no es absolutamente necesario hacer esperar al usuario, casi a todos nos ha pasado que dejamos para una segunda y hasta tercerea iteración optimizaciones como está y mientras tanto ponemos algún mensajito o código provisional mientras terminanos la iteración en que estamos.

Un abrazo hasta Morelia

martinartaza 10-11-2010 17:29:36

En mi experiencia el problema no es que demore, sino ...
 
Como digo, en mi experiencia el problema no es que demore, sino que se cuelga, me paso de tener este tipo de problema y la mejor solución de todas fue mostrar un panel con un gif y un cartel que diga espere por favor.

rgstuamigo 10-11-2010 21:13:05

Cita:

Empezado por acalderonr (Mensaje 380286)
...
Estoy usando Delphi 6, Firebird 2.1 con los componentes de la pestaña Interbase en mi máquina Core2Duo, si ejecuto un for ... while del 1 al 450mil con un IBQuery con la sentencia "insert into almacen ..." para cada vale, se tarda 52segundos en hacerlo, alguien tendrá una idea para hacerlo mas eficiente?
...

Pues yo te recomiendo que leas estas dos partes 1 y 2 de un articulo que te va guiar para esos menesteres.;) Te recomiendo leerlo sin flojear.;)
Saludos...:)


La franja horaria es GMT +2. Ahora son las 01:48:06.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi