Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Mi Consulta SQL Funciona pero tarda demasiado (https://www.clubdelphi.com/foros/showthread.php?t=95928)

duilioisola 02-11-2022 16:00:28

Mi granito de arenta:

Un simple log puede ser un procedimiento como este:
Código Delphi [-]
procedure TDMMain.Log(s: string);
var
  F : TextFile;
  FileName : string;
begin
  FileName := ChangeFileExt(Application.ExeName, '.log');
  AssignFile(F, FileName);
  try
     Append(F);
  except
     try
        Rewrite(F);
     except
        on e: Exception do
           ShowMessage('Error al abrir fichero : ' + FileName + #13#10 + e.Message);
     end;
  end;
  WriteLn(F, FormatDatetime('[yyyy-mm-dd hh:nn:ss.zzz] ', Now) + s);
  CloseFile(F);
end;

Prueba el bulce principal sin hacer nada y ves cuanto tarda.
Código Delphi [-]
with sqnominadetalle do
  begin
    close;
    SQL.Clear;
    SQL.Add('SELECT * FROM a2NominaDetalle');
    ExecSQL;
    sqnominadetalle.First;
    while not sqnominadetalle.Eof do
    begin
      Log(sqnominadetalle.FieldByName('FNM_INTEGRANTE').AsString);

      sqnominadetalle.Next;
    end;
  end;
Si es algo lógico (segundos), agregas la validación:
Código Delphi [-]
with sqnominadetalle do
  begin
    close;
    SQL.Clear;
    SQL.Add('SELECT * FROM a2NominaDetalle');
    ExecSQL;
    sqnominadetalle.First;
    while not sqnominadetalle.Eof do
    begin
      Log(sqnominadetalle.FieldByName('FNM_INTEGRANTE').AsString);
      
      cedintegrante := sqnominadetalle.FieldByName('FNM_INTEGRANTE').AsString;
      codconstante := sqnominadetalle.FieldByName('FNM_CONSTANTE').AsString;
      fnmtipo := sqnominadetalle.FieldByName('FNM_TIPO').AsInteger;
      fnmvalorperiodo := sqnominadetalle.FieldByName('FNM_VALORPERIODO').AsCurrency;
      fnmvalordefault := sqnominadetalle.FieldByName('FNM_VALORDEFECTO').AsCurrency;
      fnmdescripcion := sqnominadetalle.FieldByName('FNM_DESCRIPCIONPERIODO').AsString;
      with sqverificardetalle do
      begin
        close;
        ParamByName('PINTEGRANTE').AsString := cedintegrante;
        ParamByName('PCONSTANTE').AsString := codconstante;
        ExecSQL;
        close;
      end;
      // ShowMessage('Net');
      sqnominadetalle.Next;
    end;
  end;
Si sigue siente un tiempo lógico, prueba agregando le update.
Código Delphi [-]
with sqnominadetalle do
  begin
    close;
    SQL.Clear;
    SQL.Add('SELECT * FROM a2NominaDetalle');
    ExecSQL;
    sqnominadetalle.First;
    while not sqnominadetalle.Eof do
    begin
      Log(sqnominadetalle.FieldByName('FNM_INTEGRANTE').AsString);
      
      cedintegrante := sqnominadetalle.FieldByName('FNM_INTEGRANTE').AsString;
      codconstante := sqnominadetalle.FieldByName('FNM_CONSTANTE').AsString;
      fnmtipo := sqnominadetalle.FieldByName('FNM_TIPO').AsInteger;
      fnmvalorperiodo := sqnominadetalle.FieldByName('FNM_VALORPERIODO').AsCurrency;
      fnmvalordefault := sqnominadetalle.FieldByName('FNM_VALORDEFECTO').AsCurrency;
      fnmdescripcion := sqnominadetalle.FieldByName('FNM_DESCRIPCIONPERIODO').AsString;
      with sqverificardetalle do
      begin
        close;
        ParamByName('PINTEGRANTE').AsString := cedintegrante;
        ParamByName('PCONSTANTE').AsString := codconstante;
        ExecSQL;

        if not sqverificardetalle.IsEmpty then
        begin
          with squpdatenomina do
          begin
            ParamByName('PTIPO').AsInteger := fnmtipo;
            ParamByName('PCONSTANTE').AsString := codconstante;
            ParamByName('PINTEGRANTE').AsString := cedintegrante;
            ParamByName('PVALOR1').AsCurrency := fnmvalordefault;
            ParamByName('PVALOR2').AsCurrency := fnmvalorperiodo;
            ParamByName('PPERIODO').AsString := fnmdescripcion;
            ExecSQL;
            close;
          end
        end;

        close;
      end;
      // ShowMessage('Net');
      sqnominadetalle.Next;
    end;
  end;
Si todo está en un tiempo lógico, el problema estará en el INSERT o en UPDATE final que haces.

Finalmente, trata de traerte todo lo que necesites en el primer SELECT.
Con algo así solo deberás ver si el campo existe_integrante contiene algo o es nulo/cero y te ahorras un SQL por cada vuelta de bucle.

Código SQL [-]
select n.*,
       /* Esta parte sería lo que contiene sqverificardetalle */
       (select first 1 integrante
        from detalle
        where
        integrante = n.fnm_integrante and
        constante = n.fnm_cosntante) as existe_integrante
from a2nominadetalle n

webmasterplc 03-11-2022 13:06:33

Agradecido, hoy me voy a poner a resolver esto y les comento

webmasterplc 04-11-2022 11:17:30

Buenas Tomando la Recomendación de Todos he ido probando, al hacer el log me di cuenta que perdía tiempo en la consulta para verificar el detalle para lo cual en vez de hacerlo tome la recomendación de Casimiro Notevi
Código Delphi [-]
  
select * from tabla1;
while not tabla1.eof  
  try
    update table 2...
  except
    insert into tabla 2...
  end;
  table1.next
end;i
y usando el log que me recomendó duilioisola pude ver lo que tardaba en cada registro en mi ultima prueba tardo 48 minutos 78.648 registros creo que estaría bien dentro de los tiempos o por lo menos se me han mejorado los tiempo considerando que antes duraba 20 min con 120 registros y por tratarse de una base de datos como dbbisam

mi Codigo
Código Delphi [-]
   while not sqnominadetalle.Eof do
                                      begin

                                      cedintegrante:=sqnominadetalle.FieldByName('FNM_INTEGRANTE').AsString;
                                      codconstante:=sqnominadetalle.FieldByName('FNM_CONSTANTE').AsString;
                                      fnmtipo:=sqnominadetalle.FieldByName('FNM_TIPO').AsInteger;
                                      fnmvalorperiodo:=sqnominadetalle.FieldByName('FNM_VALORPERIODO').AsCurrency;
                                      fnmvalordefault:=sqnominadetalle.FieldByName('FNM_VALORDEFECTO').AsCurrency;
                                      fnmdescripcion:=sqnominadetalle.FieldByName('FNM_DESCRIPCIONPERIODO').AsString;

                                      try

                                                         with squpdatenomina do
                                                         begin
                                                            ParamByName('PTIPO').AsInteger:=fnmtipo;
                                                            ParamByName('PCONSTANTE').AsString:=codconstante;
                                                            ParamByName('PINTEGRANTE').AsString:=cedintegrante;
                                                            ParamByName('PVALOR1').AsCurrency:= fnmvalordefault;
                                                            ParamByName('PVALOR2').AsCurrency:=fnmvalorperiodo;
                                                            ParamByName('PPERIODO').AsString:=fnmdescripcion;
                                                            ExecSQL;
                                                            Close;
                                                         end;
        
 Log(sqnominadetalle.FieldByName('FNM_INTEGRANTE').AsString+sqnominadetalle.FieldByName('FNM_CONSTANT  E').AsString);
                                      except
                                                              with dbtsdetallenomina do
                                                               begin

                                                                tablename:='a2NominaDetalle';
                                                                Open;
                                                                Insert;
                                                                Append;
                                                                FieldByName('FNM_TIPO').AsInteger:=fnmtipo;
                                                                FieldByName('FNM_CONSTANTE').AsString:=codconstante;
                                                                FieldByName('FNM_INTEGRANTE').AsString:=cedintegrante;
                                                                FieldByName('FNM_VALORDEFECTO').AsCurrency:= fnmvalordefault;
                                                                FieldByName('FNM_VALORPERIODO').AsCurrency:=fnmvalorperiodo;
                                                                FieldByName('FNM_DESCRIPCIONPERIODO').AsString:=fnmdescripcion;
                                                                Post;
                                                                Close;

                                              Close;
                                              end;

                                      end;
                                      sqnominadetalle.Next;
                                      end;

duilioisola 04-11-2022 11:53:10

¿Has comprobado que entra alguna vez a la parte except?

Código Delphi [-]
select * from tabla1;
while not tabla1.eof  
  try
    update table 2...
  except
    Log('INSERT')
    insert into tabla 2...
  end;
  table1.next
end;

Según tengo entendido, si un update no "toca" ningún registro no falla.

mamcx 04-11-2022 14:24:07

Cita:

Empezado por webmasterplc (Mensaje 548971)
y usando el log que me recomendó duilioisola pude ver lo que tardaba en cada registro en mi ultima prueba tardo 48 minutos 78.648 registros creo que estaría bien dentro de los tiempos o por lo menos se me han mejorado los tiempo considerando que antes duraba 20 min con 120 registros y por tratarse de una base de datos como dbbisam

Esto es lo que no cuadra. Como te va a gastar 20 min por tan poco? Yo he hecho cargas de *gigabytes* en ese tiempo.

Mi app principal carga cientos de miles de registros en como 2-3 minutos, y eso contando las tardanzas de viajar por internet.

Y tengo un cliente contra dbisam. Lo único que se me ocurre es que te falta poner un indice.

Pero igual, haciendo todo en memoria y guardando debería no tomar mas de un par de segundos.

Casimiro Notevi 04-11-2022 18:11:48

Es así, eso debería tardar unos segundos, como mucho.

webmasterplc 04-11-2022 19:58:23

Cita:

Empezado por mamcx (Mensaje 548975)
Pero igual, haciendo todo en memoria y guardando debería no tomar mas de un par de segundos.

NO Tengo ni Idea e como hacer los update en memoria

mamcx 04-11-2022 22:42:08

Cita:

Empezado por webmasterplc (Mensaje 548981)
NO Tengo ni Idea e como hacer los update en memoria

Como te había explicado antes, con mas comentarios:

Cita:

Empezado por mamcx (Mensaje 548856)
Código Delphi [-]

// aqui cargas todo en memoria
mi_origen: TClientDataSet := SELECT id FROM db1.Customer 
mi_destino: TClientDataSet := SELECT * FROM db2.Customer

for row in mi_destino
begin
   // Acá resuelves todo en memoria.
   if row.id in mi_origen 
   begin
   // Existe, actualiza
  end else begin
  //No existe, inserta
  end;
end

// Con los datos resueltos, vuelcas todo:

mi_destino.save

Asi debería ser muy rapido, mas que hacer un select en cada ciclo.


webmasterplc 05-11-2022 01:21:07

Cloque un índice y bajo a los 5 minutos aunque por tratarse de dbisam creo que es un tiempo aceptable


La franja horaria es GMT +2. Ahora son las 09:03:14.

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