Ir al contenido



Foto

Aplicacion lenta al importar de Excel a MySQL

Excel

Mejor respuesta escafandra , 07 noviembre 2016 - 09:15

ProcessMessages Permite a la aplicación procesar los mensajes de Windows que están bloqueados al no poder acceder mientras trabaja un bucle pesado. En general sólo debería usarse en momentos muy puntuales siendo preferible el uso de threads para esas tareas pesadas pues te permite seguir con otras tareas de tu aplicación normalmente sin necesidad de esperar a que termine. Cuando el resultado del cálculo es necesario para seguir con otras tareas, deberás implementar un semáforo y una forma de avisar a la app y al usuario que el hilo terminó.

 

Si la tarea es muy crítica, puedes poner una barra de proceso, si no sabes cuanto tardará, puedes poner una barra de progreso infinita como en este ejemplo:


delphi
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7. Dialogs, StdCtrls, ComCtrls, ExtCtrls;
  8.  
  9. type
  10. TForm1 = class(TForm)
  11. ProgressBar1: TProgressBar;
  12. Strat: TButton;
  13. Stop: TButton;
  14. procedure FormCreate(Sender: TObject);
  15. procedure StratClick(Sender: TObject);
  16. procedure StopClick(Sender: TObject);
  17. private
  18. { Private declarations }
  19. public
  20. { Public declarations }
  21. end;
  22.  
  23. var
  24. Form1: TForm1;
  25.  
  26. implementation
  27.  
  28. {$R *.dfm}
  29.  
  30. const PBM_SETMARQUEE = WM_USER + 10;
  31.  
  32. procedure TForm1.FormCreate(Sender: TObject);
  33. begin
  34. SetWindowLong(ProgressBar1.Handle, GWL_STYLE, GetWindowLong(ProgressBar1.Handle, GWL_STYLE) or PBM_SETMARQUEE);
  35. end;
  36.  
  37. procedure TForm1.StratClick(Sender: TObject);
  38. begin
  39. SendMessage (ProgressBar1.Handle, PBM_SETMARQUEE, 1, 20); // Activa 100ms
  40. end;
  41.  
  42. procedure TForm1.StopClick(Sender: TObject);
  43. begin
  44. SendMessage (ProgressBar1.Handle, PBM_SETMARQUEE, 0, 20); // Desactiva
  45. end;
  46.  
  47. end.

Saludos.

Ir al mensaje completo


  • Por favor identifícate para responder
10 respuestas en este tema

#1 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 728 mensajes
  • LocationPinar del Río, Cuba

Escrito 02 noviembre 2016 - 02:29

Hola a todos

Pues tengo una aplicacion q importa datos de un archivo de Excel para mi BD MySQL, pero se vuelve un poco lenta al hacerlo, tanto que a veces si trato de mover la ventana por la barra de titulo, se bloquea y no responde, aunque si espero unos minutos, termina el proceso de importación correctamente

 

El archivo de excel lo exporta otra aplicación de un tercero, y de el solo necesito algunas columnas

 

Uso el componente de Excel que viene con Delphi XE7, leo la hoja de Excel y la almaceno en un array, y despues ese array lo guardo en una tabla de mi BD

 

Habra alguna forma de agilizar el proceso de importación?

 

Quizas usando varios hilos, pero nunca he trabajado con hilos. Si esta fuera una solución como lo haria?

 

 

 

Nota:

Le incorporé el componente Apha skin a la aplicación y entonces se puso peor la importación, no se puede ni hacer clic en ninguna parte, pues se "congela" hasta que termina el proceso de importacion

 

 


  • 0

#2 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 02 noviembre 2016 - 02:37

Pues utilizando TThread (Hilos) es posible que agilize un poco el proceso combinando la importación de datos por cada x registros en vez de todo de un sólo golpe.


  • 0

#3 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.484 mensajes
  • LocationMallorca

Escrito 02 noviembre 2016 - 03:04

¿ Has comprobado si el problema lo tienes leyendo el Excel o guardando en MySQL (que es lo más probable) ?. Deberías guardar los tiempos que tarda cada proceso para ver donde tienes el cuello de botella.

 

Como probablemente el problema esté en la parte de MySQL, estaría bien que nos enseñes un poco el código que utilizas. Sin saber nada de lo que haces, mis consejos genéricos son que utilices consultas parametrizadas (que no hay que preparar para cada ejecución), que solo confirmes las transacciones cada X registros (sobre los 10.000), y que desactives los triggers antes de insertar registros, así como los índices de las tablas involucradas (recreándolos al final).

 

Lo lógico es que tu cuello de botella sea de este tipo.


  • 0

#4 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 728 mensajes
  • LocationPinar del Río, Cuba

Escrito 02 noviembre 2016 - 03:04

Pues utilizando TThread (Hilos) es posible que agilize un poco el proceso combinando la importación de datos por cada x registros en vez de todo de un sólo golpe.

En eso pense, pero como ya comente, nunca he trabajado con Thread

Podrias encaminarme como hacerlo, al menos para tener la idea de  como se hace


  • 0

#5 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 728 mensajes
  • LocationPinar del Río, Cuba

Escrito 03 noviembre 2016 - 09:51

¿ Has comprobado si el problema lo tienes leyendo el Excel o guardando en MySQL (que es lo más probable) ?. Deberías guardar los tiempos que tarda cada proceso para ver donde tienes el cuello de botella.

 

Como probablemente el problema esté en la parte de MySQL, estaría bien que nos enseñes un poco el código que utilizas. Sin saber nada de lo que haces, mis consejos genéricos son que utilices consultas parametrizadas (que no hay que preparar para cada ejecución), que solo confirmes las transacciones cada X registros (sobre los 10.000), y que desactives los triggers antes de insertar registros, así como los índices de las tablas involucradas (recreándolos al final).

 

Lo lógico es que tu cuello de botella sea de este tipo.

 

Que casualidad, publicamos el post al mismo tiempo (h)

 

Pues con esto leo del Excel


delphi
  1. //--- Leer los datos del libro de Excel y guardarlos en un array ---
  2. Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
  3. CantRow:=Excel.ActiveCell.Row;
  4. CantCol:=Excel.ActiveCell.Column;
  5. RangoMatriz:=Excel.Range['A1', Excel.Cells.Item[CantRow,CantCol]].Value;

Y con esto lo guardo en la BD


delphi
  1. with ModuloBD, ModuloBD.fdtExcelSaldos do
  2. begin
  3. pbProgres.Position:=0; pbProgres.Max:=CantRow;
  4. for i:=13 to CantRow do
  5. begin
  6. lblProgreso.Caption:='Leyendo fila '+ IntToStr(i) +' de '+ IntToStr(CantRow) + ' en: ' + edtArchBalSald.Text + StringOfChar( ' ', 100);
  7. lblProgreso.Repaint;
  8. Append;
  9. for j:=1 to CantCol do
  10. begin
  11. if j = 2 then fdtExcelSaldosCuenta.Value:=RangoMatriz[i,j];
  12. if j = 5 then fdtExcelSaldosDescripcion.Value:=RangoMatriz[i,j];
  13. if j = 9 then fdtExcelSaldosSaldoInicial.Value:=RangoMatriz[i,j];
  14. if j = 21 then fdtExcelSaldosSaldoFinal.Value:=RangoMatriz[i,j];
  15. end;
  16. Post;
  17. pbProgres.Position:=i;
  18. pbProgres.Repaint;
  19. end;
  20. Refresh;
  21. end;

No se si esta será la forma mas optima


  • 0

#6 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.952 mensajes
  • LocationMéxico

Escrito 03 noviembre 2016 - 10:46

Yo agregaría una línea a tu proceso de insertar registros.


delphi
  1. Application.ProcessMessages; 

Y con esto lo guardo en la BD


delphi
  1. with ModuloBD, ModuloBD.fdtExcelSaldos do
  2. begin
  3. pbProgres.Position:=0; pbProgres.Max:=CantRow;
  4. for i:=13 to CantRow do
  5. begin
  6. lblProgreso.Caption:='Leyendo fila '+ IntToStr(i) +' de '+ IntToStr(CantRow) + ' en: ' + edtArchBalSald.Text + StringOfChar( ' ', 100);
  7. lblProgreso.Repaint;
  8. Append;
  9. for j:=1 to CantCol do
  10. begin
  11. Application.ProcessMessages; //******** Agregaría ésto *********
  12. if j = 2 then fdtExcelSaldosCuenta.Value:=RangoMatriz[i,j];
  13. if j = 5 then fdtExcelSaldosDescripcion.Value:=RangoMatriz[i,j];
  14. if j = 9 then fdtExcelSaldosSaldoInicial.Value:=RangoMatriz[i,j];
  15. if j = 21 then fdtExcelSaldosSaldoFinal.Value:=RangoMatriz[i,j];
  16. end;
  17. Post;
  18. pbProgres.Position:=i;
  19. pbProgres.Repaint;
  20. end;
  21. Refresh;
  22. end;

No se si esta será la forma mas optima

 

 
Saludos


  • 0

#7 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.404 mensajes
  • LocationRepública Dominicana

Escrito 03 noviembre 2016 - 11:54

Primero aplica la recomendación de Egostar, mientras te dejo aquí un ejemplo básico de hilo al vuelo sin probar:


delphi
  1. type
  2. TTransferencia = class(TThread) //Hilo
  3. private
  4. //Aqui pones cualquier variable
  5. procedure TransferirFromExcel; //Procedimiento, funcion, etc. que hace la migracion
  6. protected
  7. procedure execute; override;
  8. public
  9. constructor create; //tambien puedes pasarle parámetros, ejemplo: Create(Nombre: String)
  10. end;
  11.  
  12. implementation
  13.  
  14. constructor TTransferencia.Create;
  15. begin
  16. inherited Create(True);
  17. end;
  18.  
  19. procedure TTransferencia.TransferirFromExcel;
  20. begin
  21. //Proceso de transferencia
  22. end;
  23.  
  24. procedure TTransferencia.Execute;
  25. begin
  26. Synchronize(TransferirFromExcel); //Aqui ejecutas el procedimiento que hace la migracion
  27. end;

Su modo de uso sería:


delphi
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3. Transferir: TTransferencia;
  4. begin
  5. Transferir.Create; //Recordar que puedes agregar parámetros en su clase, ejemplo: Transferir.Create('archivo excel a cargar');
  6. end;

Saludos


  • 0

#8 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 728 mensajes
  • LocationPinar del Río, Cuba

Escrito 03 noviembre 2016 - 02:47

ok, muchas gracias a los dos

Probare y despues les comento


  • 0

#9 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 728 mensajes
  • LocationPinar del Río, Cuba

Escrito 07 noviembre 2016 - 08:32

Yo agregaría una línea a tu proceso de insertar registros.


delphi
  1. Application.ProcessMessages; 

 
Saludos

 

Pues agregando esa linea, salio perfecto, ya la aplicacion no se cuelga, incluso puedo acceder a otras pestañas normalmente sin problemas

 

Pero en concreto, que es lo q hace?

Cual es la lógica de esa linea?


  • 0

#10 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.838 mensajes
  • LocationMadrid - España

Escrito 07 noviembre 2016 - 09:15   Mejor respuesta

ProcessMessages Permite a la aplicación procesar los mensajes de Windows que están bloqueados al no poder acceder mientras trabaja un bucle pesado. En general sólo debería usarse en momentos muy puntuales siendo preferible el uso de threads para esas tareas pesadas pues te permite seguir con otras tareas de tu aplicación normalmente sin necesidad de esperar a que termine. Cuando el resultado del cálculo es necesario para seguir con otras tareas, deberás implementar un semáforo y una forma de avisar a la app y al usuario que el hilo terminó.

 

Si la tarea es muy crítica, puedes poner una barra de proceso, si no sabes cuanto tardará, puedes poner una barra de progreso infinita como en este ejemplo:


delphi
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7. Dialogs, StdCtrls, ComCtrls, ExtCtrls;
  8.  
  9. type
  10. TForm1 = class(TForm)
  11. ProgressBar1: TProgressBar;
  12. Strat: TButton;
  13. Stop: TButton;
  14. procedure FormCreate(Sender: TObject);
  15. procedure StratClick(Sender: TObject);
  16. procedure StopClick(Sender: TObject);
  17. private
  18. { Private declarations }
  19. public
  20. { Public declarations }
  21. end;
  22.  
  23. var
  24. Form1: TForm1;
  25.  
  26. implementation
  27.  
  28. {$R *.dfm}
  29.  
  30. const PBM_SETMARQUEE = WM_USER + 10;
  31.  
  32. procedure TForm1.FormCreate(Sender: TObject);
  33. begin
  34. SetWindowLong(ProgressBar1.Handle, GWL_STYLE, GetWindowLong(ProgressBar1.Handle, GWL_STYLE) or PBM_SETMARQUEE);
  35. end;
  36.  
  37. procedure TForm1.StratClick(Sender: TObject);
  38. begin
  39. SendMessage (ProgressBar1.Handle, PBM_SETMARQUEE, 1, 20); // Activa 100ms
  40. end;
  41.  
  42. procedure TForm1.StopClick(Sender: TObject);
  43. begin
  44. SendMessage (ProgressBar1.Handle, PBM_SETMARQUEE, 0, 20); // Desactiva
  45. end;
  46.  
  47. end.

Saludos.

Archivos adjuntos


  • 1

#11 JoAnCa

JoAnCa

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 728 mensajes
  • LocationPinar del Río, Cuba

Escrito 07 noviembre 2016 - 09:27

ProcessMessages Permite a la aplicación procesar los mensajes de Windows que están bloqueados al no poder acceder mientras trabaja un bucle pesado. En general sólo debería usarse en momentos muy puntuales siendo preferible el uso de threads para esas tareas pesadas pues te permite seguir con otras tareas de tu aplicación normalmente sin necesidad de esperar a que termine. Cuando el resultado del cálculo es necesario para seguir con otras tareas, deberás implementar un semáforo y una forma de avisar a la app y al usuario que el hilo terminó.
 
...
 
Saludos.

 
Muchas gracias por la explicación, ya me quedo todo claro
 
Tema Resuelto


Editado por JoAnCa, 07 noviembre 2016 - 09:31 .

  • 0





Etiquetado también con una o más de estas palabras: Excel