PDA

Ver la Versión Completa : Ingresar 2.789.636 registro en una tabla de forma eficiente


Chaja
03-04-2012, 17:11:07
Hola:
Bueno , tengo el siguiente esquema. Uso como motoro de BD Interbase 7.5 y prog. en Delphi 2007. Uso como conector DbExpress, y comoponetes ClientDataSet. Aca en argentina, los contribuyente que son Inscripto en la DGI, en algunos casos deben retener un impuesto adicional puede ser percepcion o retencio. La cosa es que la Direccion de rentas saca en forma mensual un padron de todos los contribuyente empadronados , con las tasas que correspone al mes en curso. El archivo biene en TXT, separado por comas cuyas columnas son :Fecha, vigencia, cuit, tasa_percepcion,tasa_retencion,vencimiento y otro mas que no biene al caso.
Bien yo lo lenanto despues de tener el archivo en la pc, con un ClientDataSet haciendo LoadFrom().
todo bien, y empiezo a procesarlo, llenando una y tabla con los mismo formatos de registro, (Fecha, vigencia, tasa,tasa..) amedida que voy leyendo disparo un sp en la base de datos y lo cargo. para saber como y por donde va hago una Application.processMesage, y voy mostradno en un label el numero de reg. pero mi inconveniente es que son 2.789.636 registros y tarda en cargar de 10horas y en lagunos casos 36 horas. la pregunat es, hay una forma mas eficiente de cargar tanta cantidad de reg en menos tiempo?

Gracias

Luis Roldan
Mar del Plata
Argentina

ElDioni
03-04-2012, 17:30:01
Hola,

lo primero que te diría es que me ha dado un poco de angustia leer tu petición por la forma en que te expresas y por las faltas de ortografía que tiene, tengo que ir descifrando lo que quieres decir, supongo que no seré el único al que le pase esto, lo segundo es que no das ninguna información de como lo estás haciendo, podrías poner algo de código, te podría decir que yo lo haría con una consulta insert pero a lo mejor ya lo estás haciendo.

Saludos.

Chaja
03-04-2012, 17:45:37
Hola eldioni, gracias por tu tiempo, te pido disculpa, soy medio atolondrado para escribir. te paso el codigo.
con esto leo el txt:


procedure TFormTasasRet_Perc.SpeedButton1Click(Sender: TObject);
var Inicio:TDateTime;
begin
inherited;
if OpenDialog.Execute Then
if OpenDialog.FileName<>'' Then
begin
Inicio:=Now;

GifCarga.Visible:=True;
GifCarga.Active :=True;
edPath.Text:=OpenDialog.FileName;
AssignFile(ArchiTxt, OpenDialog.FileName);
Reset(ArchiTxt);
MemoText.Lines.LoadFromFile(OpenDialog.FileName);
lbReg.Caption:=IntToStr(MemoText.Lines.Count-1);
lbTiempoLectua.Caption:=TimetoStr(inicio-now)
end
else
ShowMessage('No hay archivo Seleccionado');
GifCarga.Visible:=False;
GifCarga.Active :=False;

end;



y con este hago el proceso de carga


procedure TFormTasasRet_Perc.LeerTxtExecute(Sender: TObject);
VAR S:String;
aux:Real;
posicion:Integer;
begin
inherited;
if MemoText.Lines.Count<=0 Then
Raise Exception.Create('No hay datos para procesar...');
GifProceso.Visible:=True;
GifProceso.Animate:=True;
if chbBorrarDatos.Checked then
begin
Borrar.Execute;
end;
CDSTasas.Close;
CDSTasas.Open;
btCancelar.Enabled:=True;
btSalir.Enabled :=False;
if ComboBox1.ItemIndex=0 Then
DecimalSeparator:=','
else
if ComboBox1.ItemIndex=1 Then
DecimalSeparator:='.';

lbinicio.Caption:=TimeToStr(Now);

for posicion:=0 to MemoText.Lines.Count-1 do
begin
Application.ProcessMessages;
lbNroReg.Caption:=IntToStr(posicion);
Sleep(1);
s:=MemoText.Lines[posicion];
if cancelado=False Then
begin
CDSTasas.Append;
CDSTasasFECHA.AsDateTime :=StrToDateTime(FormatDateTime('dd/mm/yyyy',StrToDate( (Copy(s,1,2) +'/'+ Copy(s,3,2) +'/'+ Copy(s,5,4) ))));
CDSTasasDESDE.AsDateTime :=StrToDateTime(FormatDateTime('dd/mm/yyyy',StrToDate( (Copy(s,10,2) +'/'+ Copy(s,12,2) +'/'+ Copy(s,14,4) ))));
CDSTasasHASTA.AsDateTime :=StrToDateTime(FormatDateTime('dd/mm/yyyy',StrToDate( (Copy(s,19,2) +'/'+ Copy(s,21,2) +'/'+ Copy(s,23,4) ))));
CDSTasasCUIT.Value :=Copy(s,28,2)+'-'+Copy(s,30,8)+'-'+copy(s,38,1);
CDSTasasTIPO_CONVENIO.Value := Copy(s,40,1);
CDSTasasESTADO.Value := Copy(S,42,1);
CDSTasasCAMBIO_ALICUOTA.Value:= Copy(s,44,1);

CDSTasasTASA_PERCEPCION.AsFloat := StrToFloat(copy(s,46,4));
CDSTasasTASA_RETENCION.AsFloat := StrToFloat(Copy(s,51,3));
CDSTasasGRUPO_PERCEPCION.AsFloat:= StrToInt(Copy(s,56,2));
CDSTasasGRUPO_RETENCION.AsFloat := StrToInt(Copy(s,59,2));

CDSTasas.Post;

spGravar.close;
spGravar.ParamByName('cuit').Value := CDSTasasCUIT.Value;
spGravar.ParamByName('fecha').AsDate := CDSTasasFECHA.AsDateTime;
spGravar.ParamByName('desde').AsDate := CDSTasasDESDE.AsDateTime;
spGravar.ParamByName('hasta').AsDate := CDSTasasHASTA.AsDateTime;
spGravar.ParamByName('tipo').Value := CDSTasasTIPO_CONVENIO.Value;
spGravar.ParamByName('estado').Value := CDSTasasESTADO.Value;
spGravar.ParamByName('cambio').Value := CDSTasasCAMBIO_ALICUOTA.Value;
spGravar.ParamByName('tasa_perc').AsFloat := CDSTasasTASA_PERCEPCION.AsFloat;
spGravar.ParamByName('tasa_ret').AsFloat := CDSTasasTASA_RETENCION.AsFloat;

spGravar.ParamByName('g_per').Value := CDSTasasGRUPO_PERCEPCION.Value;
spGravar.ParamByName('g_ret').Value := CDSTasasGRUPO_RETENCION.Value;
spGravar.ExecProc;
end
else
if MessageDlg('cotinua ?',mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin
btCancelar.Enabled:=True;
btSalir.Enabled :=False;
GifProceso.Visible:=True;
GifProceso.Animate:=True;
cancelado:=False;
end
else
exit;
end;
DecimalSeparator:='.';
GifProceso.Visible:=False;
GifProceso.Animate:=False;
lbfin.Caption:=TimeToStr(now);

btCancelar.Enabled:=False;

btSalir.Enabled :=True;
end;




gracias

Casimiro Notevi
03-04-2012, 17:45:51
Pues sí, ha costado trabajo leerlo ;)
Resumiendo, dices que lees un fichero de texto y que tarda 10 horas y otras veces 36 horas.

¿Y? ;)

Edito: se te ha enrevesado el código :D
A ver si puedes arreglarlo, en caso contrario, envíalo a nuestro email y te lo copio y pego para que salga correctamente.

Chaja
03-04-2012, 19:24:01
ahi corregi el codigo que no se veia...

jlrbotella
03-04-2012, 19:52:16
1) Para leer un fichero tan grande no uses el componente tmemo. Puedes usar:

var f : TextFile;
lineaactual : string;
begin
AssignFile('c:\test.txt', f);
try
Append(f);
while not Eof do begin
Readln(f, lineaactual); //creo que es así, busca en la ayuda de Delphi para asegurarte
//aqui haces lo que quieras con lineaactual
end;
finally
Closefile(f);
end;
end;
2º He visto un sleep(1). Tienes que eliminarlo.

Casimiro Notevi
03-04-2012, 20:06:45
1) Para leer un fichero tan grande no uses el componente tmemo. Puedes usar:

var f : TextFile;
lineaactual : string;
begin
AssignFile('c:\test.txt', f);
try
Append(f);
while not Eof do begin
Readln(f, lineaactual); //creo que es así, busca en la ayuda de Delphi para asegurarte
//aqui haces lo que quieras con lineaactual
end;
finally
Closefile(f);
end;
end;
2º He visto un sleep(1). Tienes que eliminarlo.

Me parece perfecto.
Además también quitaría el application.processmessages o que solamente lo hiciera cada ¿1000? registros.
if contador mod 100 then application.processmessages

Otra cosa, me ha parecido que lees a un clientdataset y luego sus valores lo pasas como parámetros a un stored procedure, ¿por qué no lo haces directamente?

Chaja
04-04-2012, 05:09:26
El CDS, lo puse para que el user vea como se carga... no se... y el memo lo puse para que se vea el archivo a cargar.
si el sleep() lo puedo sacar, aunque es un milisegundo ....mmmm....si pero si saco bien la cuenta son como 45 minutos no?

olbeup
04-04-2012, 09:11:32
Por que no muestras de 1..10 registros de esos 2.789.636 que tienes para ver otra forma de ayudarte.
El motor que usas es Interbase 7.5 el mio es SQL SERVER 2005, en ocasiones tengo que incorporar un fichero de texto más o menos parecido al tuyo, sólo que éste es de combustible y lleva 7 campos que tengo que extraer, hay fichero que tienen 2095 registro y sólo dura en leerlo 1 segundo, en tu caso (2.789.636 / 2095) = (1.331,5685 / 60) = 22,224 Seg. NO 10..36 Horas.

En SQL SERVER se crean dos ficheros que se llaman schema.ini y dgi.txt en tu caso.

Estructuras del fichero schema.ini
[dgi.txt]
ColNameHeader=True
Format=Delimited(,)
CharacterSet=ANSI
Col1=Fecha Date
Col2=Vigencia Date
Col3=Cuit Char 11
Col4=Tasa_Percepcion Double
Col5=Tasa_Retencion Double
Col6=Vencimiento Date


Líneas del fichero dgi.txt
Fecha, Vigencia, Cuit, Tasa_percepcion, Tasa_retencion, Vencimiento
........, ..........., ....., ......................, ....................., ...............
........, ..........., ....., ......................, ....................., ...............
........, ..........., ....., ......................, ....................., ...............

Mira si puedes hacer algo parecido para Interbase

Un saludo

Casimiro Notevi
04-04-2012, 10:46:02
El CDS, lo puse para que el user vea como se carga... no se... y el memo lo puse para que se vea el archivo a cargar.
si el sleep() lo puedo sacar, aunque es un milisegundo ....mmmm....si pero si saco bien la cuenta son como 45 minutos no?

En un proceso de ese tipo, el estar mostrando información al usuario es perder tiempo. En todo caso una barra de progreso, no más.
Quita todo lo que no sirva, la carga en el CDS la quitas también, el sleep no es un milisegundo realmente, además de que no sirve para nada.
Resumiendo, lo más simple y eficaz.

fjcg02
04-04-2012, 11:16:26
Además de eso, una sola instrucción insert parametrizada, para que la bbdd sólo la precompile una vez.


Saludos

Casimiro Notevi
04-04-2012, 11:33:47
Además de eso, una sola instrucción insert parametrizada, para que la bbdd sólo la precompile una vez.
Saludos

También, esa llamada al 'stored procedure' no tiene pinta de ser muy efectiva.
Creo que sería mejor un ibsql/fibsql/etc. precompilada (.prepare).

ecfisa
04-04-2012, 13:43:57
Hola.

Otra cosa que puede ayudar:

if posicion mod 100 = 0 then
CDSTasas.MergeChangeLog;


Saludos.

Edito: Una consulta, ¿ Las líneas tienen una longitud fija de caracteres ?

Chaja
04-04-2012, 15:24:16
si la estructura del txt, es de tamaño fijo cada linea.
Voy a probar , sacare el Sp. y pondre un TSQLQUery, creia que era mas eficiente hacerlo con el storeProcedure, lo que no enentedi lo tuyo olbeup


Por que no muestras de 1..10 registros de esos 2.789.636 que tienes para ver otra forma de ayudarte.
El motor que usas es Interbase 7.5 el mio es SQL SERVER 2005, en ocasiones tengo que incorporar un fichero de texto más o menos parecido al tuyo, sólo que éste es de combustible y lleva 7 .....


pruebo y aviso....

Casimiro Notevi
04-04-2012, 16:03:54
Voy a probar , sacare el Sp. y pondre un TSQLQUery, creia que era mas eficiente hacerlo con el storeProcedure, lo que no enentedi lo tuyo olbeup

En principio déjalo, haz pruebas y ya decides si usar uno u otro.

PepeLolo
12-04-2012, 19:52:35
Para el proyecto "(DELT@) Declaración Electrónica de Trabajadores Accidentados" en el que trabaje, se realizaba la carga de un XML desmesurado. Lo que se hizo fue cargar el fichero en una tabla temporal de Oracle en este caso (para que sea más pequeña la carga del fichero txt, lo puedes realizar en partes más pequeñas). La carga real de los datos se realizaba en un SP (procedimiento almacenado).

Como se ejecuta todo en el servidor y no tiene que viajar información por la red, el tiempo que ganas es mucho.

un saludo.