Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Conexión con bases de datos
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Conexión con bases de datos

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 01-07-2014
Avatar de hgiacobone
hgiacobone hgiacobone is offline
Miembro
 
Registrado: may 2003
Ubicación: La Plata, Bs. As., Argentina
Posts: 165
Poder: 21
hgiacobone Va por buen camino
Importar padron ARBA 2014

Hola,
Disculpen esta entrada pero tal vez alguno de ustedes tal vez manejan la trilogía DB_Firebird + Delphi + FIBPlus , o similar.

La consulta es para los residentes de BsAs. y es:
¿Han intentado importar el padron de ARBA con el nuevo formato 2014?


Son 2 archivos y cada archivo contiene algo de 3.222.000 registros delimitados por "punto y coma", aunque yo lo accedo por posiciones fijas.
De alli solo extraigo el "Nro. CUIT" y la "Alicuota" que transfiero a una tabla puntual de mi DB.

Son solo 2 archivos TXT, pero la incorporación a mi DB es muy lenta. Tarda unas 18 horas en procesar los dos archivos.

Existe alguna manera de realizarlo medianamente veloz ?
Gracias de antemano,
YAKO
__________________
Gracias de antemano por vuestra ayuda.
·.:*:.·Yako·.:*:.·
Responder Con Cita
  #2  
Antiguo 01-07-2014
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.037
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Con toda seguridad la lentitud se produce en la lectura del archivo de texto. tal vez si lo cargaras completo en memoria, se aceleraría el proceso.
No soy de Buenos Aires, aunque conozco bien delphi-fibplus-firebird
Pero si solamente te pueden contestar los de Buenos Aires... tenías que haber puesto la pregunta en buenosairesclubdelphi.ba
Responder Con Cita
  #3  
Antiguo 01-07-2014
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Hola

Yo tampoco soy de BsAs, pero he usado algunas veces la importación de archivos TXT.

Será que cada vez que agregas un registro abres tabla/base de datos, ingresas el registro, generas el POST, haces un commit cierras tabla/base de datos???, esto multiplicado por dos archivos con mas de 3 millones de registros, puede que sea lento.

Si no es eso, no se que mas pueda ser.

Saludos
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney

Última edición por egostar fecha: 01-07-2014 a las 17:27:54.
Responder Con Cita
  #4  
Antiguo 01-07-2014
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.037
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Aunque lo primero de todo es que ponga aquí el código fuente para que veamos cómo trabaja.
Responder Con Cita
  #5  
Antiguo 01-07-2014
[egostar] egostar is offline
Registrado
 
Registrado: feb 2006
Posts: 6.556
Poder: 25
egostar Va camino a la fama
Cita:
Empezado por Casimiro Notevi Ver Mensaje
Aunque lo primero de todo es que ponga aquí el código fuente para que veamos cómo trabaja.
Si claro, con eso se puede ayudar mas y mejor

Saludos
__________________
"La forma de empezar es dejar de hablar y empezar a hacerlo." - Walt Disney
Responder Con Cita
  #6  
Antiguo 01-07-2014
cloayza cloayza is offline
Miembro
 
Registrado: may 2003
Ubicación: San Pedro de la Paz, Chile
Posts: 913
Poder: 22
cloayza Tiene un aura espectacularcloayza Tiene un aura espectacular
Yo estoy mas cerca así que mi respuesta debería llegar mas rápido...

Bueno fuera de bromas, amigo como dicen los colegas comparte un poco de código para ver que podría estar provocando la lentitud...

Un abrazo.
Responder Con Cita
  #7  
Antiguo 02-07-2014
Avatar de hgiacobone
hgiacobone hgiacobone is offline
Miembro
 
Registrado: may 2003
Ubicación: La Plata, Bs. As., Argentina
Posts: 165
Poder: 21
hgiacobone Va por buen camino
Thumbs up Solucionado

Gracias a todos por participar.
Nobleza obliga, les dejo como lo hice.

Tuve que optimizar los StoreProc de la base de datos y el codigo, pero funciona bien. En 1 Hs está procesado.

En la Db de Firebird cree 2 tablas temporales (una para cada alicuota) sin indexar, con campo CUIT y ALICUOTA.
Mi tabla del padron principal tiene 3 campos: CUIT / Ali_Percep / Ali_Reten indexado con clave sobre el primero.

El proceso se hace desde el sistema disparando diferentes SP en la DB.
Primero un SP hace el borrado de las tablas temporales.
Luego cargo en un TStringList uno de los archivos para obtener los datos necesarios y almacenarlos en la tabla temporal correspondiente con un proceso similar a este:

<DELPHI>
Código Delphi [-]
var
    InicioSesion, FinSesion: TDateTime;
    s, m, sMsgErrores, sCuit: string;
    sAliPer,sAliRet:string;
    MyStringList:TStringList;
    n,i,Max:integer;
Begin

    InicioSesion:= Now;

    MyStringList := TStringList.Create;
    i:=0;
    progress1.Min:=0;
    progress1.Position:=0;
    MyStringList.LoadFromFile( 'x:\padron_retenciones.txt' );

     progress1.Min:=0;
     progress1.Max:= MyStringList.Count;
     progress1.Position:=0;

                DM.SP100.StoredProcName:='SP_TEMP_PER_INS';
                DM.SP101.StoredProcName:='SP_TEMP_RET_INS';
                DM.WriteTrans.StartTransaction;   //Transaccion inicial

                for i:=0 to MyStringList.Count-1 do
                begin
                  Application.ProcessMessages;

{Este es el metodo para acceder por campo delimitado
    MyStringList.Delimiter := '|';
    MyStringList.StrictDelimiter := True;
    MyStringList.DelimitedText := LineaDelArchivoDelimitado; // R|20100707121|1|2|000-0000000-0|16| ;
    Tabla.Campo1.Value := MyStringList[0];
    Tabla.Campo2.Value := MyStringList[1];
}

{Este es el metodo por posicion fija}
                  s:=MyStringList[i];
                  sCuit  :=Copy(s,30,11);
                  sAliRet:='0';
                  sAliPer:='0';

                  if ( (s[1]='P' {Percep}) or (s[1]='R' {Retenciones}) ) then
                  begin
                      if (s[1]='P')
                       then sAliPer:=Copy(s,48,4)
                        else sAliRet:=Copy(s,48,4);

                      LInfo.Caption:=Format('Procesando registro %d de %d... (CUIT %s)', [i, Max, sCuit ]);
                      Pinfo.Refresh;

                      progress1.Position:= i;

                          if (s[1]='P') then
                          begin
                          DM.SP100.ParamByName('Cuit').AsString   := sCuit;
                          DM.SP100.ParamByName('Alicuota').AsFloat:= StrToCurr(Copy(sAliPer,1,1)+'.'+Copy(sAliPer,3,2));
                          DM.SP100.Prepare;
                          DM.SP100.ExecProc;
                          end
                          else begin
                          DM.SP101.ParamByName('Cuit').AsString   := sCuit;
                          DM.SP101.ParamByName('Alicuota').AsFloat:= StrToCurr(Copy(sAliRet,1,1)+'.'+Copy(sAliRet,3,2));
                          DM.SP101.Prepare;
                          DM.SP101.ExecProc;
                          end;


                          //graba cada 500 registros
                          IF ((i mod 500) = 0) THEN
                          BEGIN
                            TRY
                              LInfo.Caption:=Format('Grabando bloque %d/%d...', [i, Max ]);
                              Pinfo.Refresh;

                              if (DM.WriteTrans.InTransaction) then
                              begin
                                 DM.WriteTrans.Commit;
                                 DM.WriteTrans.StartTransaction;  //Inicia una Trans consecutiva
                              end
                              else DM.WriteTrans.StartTransaction;  //Fuerza iniciar una Trans
                            Except
                              on E:Exception do
                              begin
                               DM.WriteTrans.Rollback;
                               Bien:= FALSE;
                               PInfo.Visible:=False;
                               sMsgErrores:= sMsgErrores + 'Error al grabar bloque de datos.'#13+E.Message;
                               Break;
                              end;
                            End;
                          END;
                  end;
                end;{lineas_del_archivo}


                //Compruebo si hay un resto sobre ultimos 500 con transac activa los guarda tambien
                if (DM.WriteTrans.InTransaction) then
                begin
                  TRY
                    DM.WriteTrans.Commit;
                  Except
                    on E:Exception do
                    begin
                     DM.WriteTrans.Rollback;
                     Bien:= FALSE;
                     PInfo.Visible:=False;
                     sMsgErrores:= sMsgErrores + 'Error al guardar el RESTO.'#13+E.Message;
                     Break;
                    end;
                  End;
                end;



Si todo anduvo bien (yo utilizo banderas de status, pero lo anterior puede encapsularse en una funcion que devuelva True/False y obrar en consecuencia) entonces unimos mediante otro SP encargado de unir en el padron definitivo las alicuotas existentes en las dos tablas temporales:

Código Delphi [-]
              Linfo.Caption:='Guardando datos. Aguarde...';
              PInfo.Refresh;

              DM.WriteTrans.StartTransaction;
              TRY
                DM.SP101.StoredProcName:='';
                DM.SP101.StoredProcName:='SP_PADRON_MERGE';
                DM.SP101.ExecProc;
                DM.WriteTrans.Commit;

                  Linfo.Caption:='Verificando clientes...';
                  PInfo.Refresh;

                  Actualizar_Alicuotas_Clientes; //actaulizamos Tabla clientes

                  FinSesion:= Now;
                  m:= Format('(Tiempo: %s)', [ TimeToStr(FinSesion - InicioSesion) ]);

                  Linfo.Caption:='Importación Finalizada - ' + m;
                  PInfo.Refresh;

                  Application.MessageBox(PChar('Proceso finalizado correctamente.'#13 + m),
                    'Aviso', MB_OK+MB_ICONINFORMATION);

              Except
                on E:Exception do
                begin
                 DM.WriteTrans.Rollback;
                 Bien:= FALSE;
                 PInfo.Visible:=False;
                 MessageDlg('Error al actualizar el padrón.'#13#13'Tipo de error:'#13+E.Message, mtError, [mbOk],0);
                end;
              End;
end;


------
<FIREBIRD>

En la DB, el SP encargado de unir a la tabla del Padron definitivo las alicuotas existentes en las dos tablas temporales es esto:

Código SQL [-]
Create or Alter Procedure SP_PADRON_MERGE
as
declare variable sCUIT char(13);
declare variable nP numeric(6,2);
declare variable nR numeric(6,2);
begin
/*
  Se utiliza cuando las alicuotas vienen en 2 archivos separados.
*/

--Paso 1: borramos padron anterior
 execute procedure SP_PADRON_DEL;

--Paso 2: Insertamos toda la tabla de Retenciones
   INSERT INTO PADRON (CUIT, ALICUOTA_RETENCION, ALICUOTA_PERCEPCION)
          SELECT R.cuit, coalesce(R.alicuota,0), 0
          FROM TEMP_RETEN R ;

--Paso 3: Buscamos e insertamos desde tabla Percepciones
   For
     Select T.cuit, coalesce(T.alicuota,0) From TEMP_PERCEP T
     Into :sCUIT, :nP
     Do
     Begin
       Select P.ALICUOTA_RETENCION from PADRON P
       Where (P.CUIT = :sCUIT)
       Rows 1 to 1
       into :nR ;

       UPDATE or INSERT INTO PADRON (CUIT, ALICUOTA_RETENCION, ALICUOTA_PERCEPCION)
       VALUES (:sCUIT, coalesce(:nR, 0) , coalesce(:nP, 0) )
       MATCHING (CUIT);
     End
end;

Saludos a la comunidad,
__________________
Gracias de antemano por vuestra ayuda.
·.:*:.·Yako·.:*:.·
Responder Con Cita
  #8  
Antiguo 02-07-2014
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.037
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Ufff... yo haría todo bastante diferente
Para empezar quitaba ese Application.ProcessMessages porque lo enlentece muchísimo (pondría simplemente el cursor del ratón con el reloj de arena).
Tampoco haría un commit cada 500 registros, si son varios millones, los haría al menos cada diez mil o algo así, tendría que hacer pruebas.
Además aprovecharía en ese instante que hace commit para hacer el application.processmessages
Luego, lo de pasar a un stringlist y luego a una tabla en memoria... no acabo de entenderlo, en principio me parece trabajo doble.
En fin, que tendría que conocer mejor todo lo que haces para decidir una cosa u otra.
Responder Con Cita
  #9  
Antiguo 03-07-2014
cloayza cloayza is offline
Miembro
 
Registrado: may 2003
Ubicación: San Pedro de la Paz, Chile
Posts: 913
Poder: 22
cloayza Tiene un aura espectacularcloayza Tiene un aura espectacular
Estimado hgiacobone si me lo permite, quisiera proponer algunos cambios, pienso que podría mejorar el rendimiento.

1) Leer el archivo de texto sin pasar por la carga de este a un TStringList.
2) Evitar el uso de tablas temporales y realizar la inserción o actualización en la tabla final (PADRON)
3) Modificar procedimiento almacenado que realiza el merge de las tablas temporales.

Por supuesto puede ser que mi mirada no cumpla con sus requerimientos, A ver que le parecen.

Código Delphi [-]
Const
     COMMIT_RECORD=10000;
var
  InicioSesion, FinSesion: TDateTime;
  s, m, sMsgErrores, sCuit: string;
  sAliPer,sAliRet:string;
  //MyStringList:TStringList;
  n,i,Max:integer;

  {Definicion de variable para archivo de texto}
 fTextFile:TextFile;
  value:single;

    {Funcion que cuenta las lineas que tiene el archivo de texto}
    Function LineasCount:Integer;
    Var
       Line:String;
    Begin
         Result:=0;
         while Not Eof(fTextFile) do
         Begin
              ReadLn(fTextFile,Line);
              Inc(Result);
         End;
         Reset(fTextFile);
    End;[/color]

Begin
    InicioSesion:= Now;

    //MyStringList := TStringList.Create;

    i:=0;
    progress1.Min:=0;
    progress1.Position:=0;

    AssignFile(fTextFile,'x:\padron_retenciones.txt');
    Reset(fTextFile);[/color]

    progress1.Min     := 0;
    progress1.Max     := LineasCount(); //MyStringList.Count;
    progress1.Position:= 0;

    DM.WriteTrans.StartTransaction;

    {Ciclo principal de lectura del archivo de texto}
    While Not Eof(fTextFile) Do
    begin
         {Lectura de una linea}
         ReadLn(fTextFile, s);

         Progress1.Position:= i;

         Application.ProcessMessages;

         sCuit  :=Copy(s,30,11);
         sAliRet:='0';
         sAliPer:='0';

         {Este trozo de código tambien se puede mejorar...}
         if (s[1]='P') then
         begin
             sAliPer:=Copy(s,48,4);
             Value:=StrToCurr(Copy(sAliPer,1,1)+'.'+Copy(sAliPer,3,2));
         end
         else
         begin
             sAliRet:=Copy(s,48,4);
             Value:=StrToCurr(Copy(sAliPer,1,1)+'.'+Copy(sAliPer,3,2));
         end;

         {Llamada al procediento que realiza la inserción p actualización}
         DM.SP100.StoreProcName:='SP_PADRON_MERGE';
         DM.SP100.ParamByName('Tipo').AsString   := s[1];
         DM.SP100.ParamByName('Cuit').AsString   := sCuit;
         DM.SP100.ParamByName('Alicuota').AsFloat:= Value;
         DM.SP100.Prepare;
         DM.SP100.ExecProc;

         if ((i mod COMMIT_RECORD) = 0) then
         begin
             try
                LInfo.Caption:=Format('Grabando bloque %d/%d...', [i, Max ]);
                Pinfo.Refresh;

                if (DM.WriteTrans.InTransaction) then
                begin
                     DM.WriteTrans.Commit;
                     DM.WriteTrans.StartTransaction;  //Inicia una Trans consecutiva
                end
                else
                    DM.WriteTrans.StartTransaction;  //Fuerza iniciar una Trans
             Except
               on E:Exception do
               begin
                    DM.WriteTrans.Rollback;
                    Bien:= false;
                    PInfo.Visible:=False;
                    sMsgErrores:= sMsgErrores + 'Error al grabar bloque de datos.'#13+E.Message;
                    Break;
               end;
             end;
         end;
    end;{lineas_del_archivo}


    //Compruebo si hay un resto sobre ultimos 500 con transac activa los guarda tambien
    if (DM.WriteTrans.InTransaction) then
    begin
         try
            DM.WriteTrans.Commit;
         except
           on E:Exception do
           begin
                DM.WriteTrans.Rollback;
                Bien:= false;
                PInfo.Visible:=False;
                sMsgErrores:= sMsgErrores + 'Error al guardar el RESTO.'#13+E.Message;
                Break;
           end;
         end;
    end;

    Linfo.Caption:='Guardando datos. Aguarde...';
    PInfo.Refresh;

    DM.WriteTrans.StartTransaction;
    TRY
        {Ya no sería necesario porque ya esta todo junto}

        {DM.SP101.StoredProcName:='';
        DM.SP101.StoredProcName:='SP_PADRON_MERGE';
        DM.SP101.ExecProc;
        DM.WriteTrans.Commit;}

        Linfo.Caption:='Verificando clientes...';
        PInfo.Refresh;

        Actualizar_Alicuotas_Clientes; //actaulizamos Tabla clientes

        FinSesion:= Now;
        m:= Format('(Tiempo: %s)', [ TimeToStr(FinSesion - InicioSesion) ]);

        Linfo.Caption:='Importación Finalizada - ' + m;
        PInfo.Refresh;

        Application.MessageBox(PChar('Proceso finalizado correctamente.'#13 + m),
          'Aviso', MB_OK+MB_ICONINFORMATION);

    Except
      on E:Exception do
      begin
       DM.WriteTrans.Rollback;
       Bien:= FALSE;
       PInfo.Visible:=False;
       MessageDlg('Error al actualizar el padrón.'#13#13'Tipo de error:'#13+E.Message, mtError, [mbOk],0);
      end;
    End;
end;

Código SQL [-]

Create or Alter procedure SP_PADRON_MERGE (
    TIPO char(10),
    CUIT integer,
    ALICUOTA integer)
as
begin
     if (Tipo='R') then
        UPDATE or INSERT INTO PADRON (CUIT, ALICUOTA_RETENCION) VALUES (:CUIT, :ALICUOTA ) MATCHING (CUIT);
     else
        UPDATE or INSERT INTO PADRON (CUIT, ALICUOTA_PERCEPCION) VALUES (:CUIT, :ALICUOTA ) MATCHING (CUIT);
end

Espero que mi pequeño aporte le ayude a mejorar el rendimiento de su proceso.

NOTA: Tome en cuenta que el conteo de las lineas del archivo para mostrar la barra de progreso puede ser omitida para mejorar mas el rendimiento

Saludos cordiales
Responder Con Cita
  #10  
Antiguo 10-07-2014
Avatar de hgiacobone
hgiacobone hgiacobone is offline
Miembro
 
Registrado: may 2003
Ubicación: La Plata, Bs. As., Argentina
Posts: 165
Poder: 21
hgiacobone Va por buen camino
Gracias
Cita:
cloayza
por tu atenta sugerencia y a todos los que han colaborado aportando ideas.
__________________
Gracias de antemano por vuestra ayuda.
·.:*:.·Yako·.:*:.·
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Delphi RoadMap 2014 - disponible! el-mono Noticias 13 06-04-2014 22:37:22
El USB del futuro llega en 2014 nlsgarcia La Taberna 2 12-12-2013 11:37:31
Padrón telefónico rruffino SQL 2 09-08-2008 16:27:02
Padron fotografico alcides Varios 1 13-10-2007 18:39:26
Más problema padrón observador adpa OOP 5 07-02-2007 20:19:15


La franja horaria es GMT +2. Ahora son las 05:55:30.


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
Copyright 1996-2007 Club Delphi