Importação de dados.. .txt para .gdb muito lento.
Olá pessoal,
gostaria da opinião dos colegas do fórum, to precisando importar txt´s para o meu banco de dados .gdb, estou usando os txt´s com campos definidos, tipo ex. abaixo, estou usando importação via mapeamento, tipo, posição inicial, tamanho e tipo de campo, só que o problema que o sistema tá demorando muito pra fazer a importação de arquivos grandes, (só importa de 500 em 500), gostaria de resolver a lentidão do processo de importação. Vou postar a rotina de importação. Estou usando DBExpress, SQLConnection, SqlDataSet, DataSetProvider e ClientDataSet.
Se alguém tiver alguma sugestão aí, será de grande valia.
Obrigado
gostaria da opinião dos colegas do fórum, to precisando importar txt´s para o meu banco de dados .gdb, estou usando os txt´s com campos definidos, tipo ex. abaixo, estou usando importação via mapeamento, tipo, posição inicial, tamanho e tipo de campo, só que o problema que o sistema tá demorando muito pra fazer a importação de arquivos grandes, (só importa de 500 em 500), gostaria de resolver a lentidão do processo de importação. Vou postar a rotina de importação. Estou usando DBExpress, SQLConnection, SqlDataSet, DataSetProvider e ClientDataSet.
// ao abrir o arquivo a ser importado no menu principal do importador.. procedure TfrmPrincipal.btnImportarClick(Sender: TObject); var txt : TStrings; begin if OpenDialog1.Execute then begin txt := TStringList.Create; Try txt.LoadFromFile(OpenDialog1.FileName); if txt.Count = 0 then raise Exception.Create(´Arquivo Vazio´); TxtToDataSet(txt,nil,ClientDataSet1,ClientDataSet2); Finally txt.Free; End; ShowMessage(´Processamento de Importação concluído com sucesso!!!´); end; end;
// função para o procedimento de importação
procedure TxtToDataSet(Arquivo, Log : TStrings; Destino, Map : TDataSet);
var
i : integer;
Campo : String;
begin
{* Varre o arquivo texto *}
for I := 1 to Arquivo.Count - 1 do
begin
Destino.Append;
(* para todos os campos a serem mapeados *)
Try
Map.First;
while not Map.Eof do
begin
(* Extrai campo conforme especificações de mapeamento *)
Campo := copy(Arquivo[i],
Map.FieldByName(´POSI´).AsInteger,
Map.FieldByName(´TAM´).AsInteger);
(* Mapeia campo Text para TField *)
TxtToField(Campo,Destino.FieldByName(Map.FieldByName(´CAMPO´).AsString),
Map.FieldByName(´TIPO´).AsString[1]);
Map.Next;
end;
destino.Post;
Except
on E : Exception do // trata a excessão e não propaga...
begin
if Log <> nil then
Log.Add(Format(´Erro na linha ¬d : ¬s´,[i,E.Message]));
// Destino.Cancel;
end;
End;
end;
end;
// função para formação dos campos dependendo o tipo de campo. procedure TxtToField(Text : string; Field : TField; Tipo : Char); var Dia, Mes, Ano : Word; begin case tipo of ´M´ : Field.AsCurrency := StrToCurr(Text); ´D´ : begin Dia := StrToInt(copy(Text,1,2)); Mes := StrToInt(copy(Text,3,2)); Ano := StrToInt(copy(Text,5,4)); Field.AsDateTime := EncodeDate(Ano, Mes, Dia); end; ´A´,´N´ : Field.AsString := Text; end; end;
Se alguém tiver alguma sugestão aí, será de grande valia.
Obrigado
Gtts
Curtidas 0
Respostas
Eniorm
09/06/2008
na lista delphi-br rolou um assunto semelhante onde uma pessoa tinha uma grande quantidade de arquivos txt para serem importados pelo banco.
o problema de lentidão estava associado ao fato de que, no caso dele, era aberto uma transação no início, e a mesma só era fechada com commit no final do processamento do arquivo.
neste caso, foi resolvido acrescentando uma variável inteiro com o objetivo de servir de contador, onde era estipulado por exemplo, ao completar 500 inserts, era aplicado um commit, e zerado este contador.
tente implementar algo do tipo, talvez resolve ou pelo menos melhora
o problema de lentidão estava associado ao fato de que, no caso dele, era aberto uma transação no início, e a mesma só era fechada com commit no final do processamento do arquivo.
neste caso, foi resolvido acrescentando uma variável inteiro com o objetivo de servir de contador, onde era estipulado por exemplo, ao completar 500 inserts, era aplicado um commit, e zerado este contador.
tente implementar algo do tipo, talvez resolve ou pelo menos melhora
GOSTEI 0
Cerqueira_r
09/06/2008
Bom Dia,
Estou buscando formas de melhorar meu aplicativo de importação de arquivos, atualmente estou utilizando o BDS2006 com banco de dados Postgre 8.2.
Os arquivos que são importados pelo sistema possuem aproximadamente 50Mb, cerca de 300 Mil linhas. Utilizo o componente Zeos com clientdataset.
Tentei modificar o aplicativo para realizar o processo por threads, porém ainda não consegui criar um pool de conexão para sustentar cada thread executada.
Se alguém souber de alguma dica onde possa encontrar referências sobre o assunto, eu gradeço.
Estou buscando formas de melhorar meu aplicativo de importação de arquivos, atualmente estou utilizando o BDS2006 com banco de dados Postgre 8.2.
Os arquivos que são importados pelo sistema possuem aproximadamente 50Mb, cerca de 300 Mil linhas. Utilizo o componente Zeos com clientdataset.
Tentei modificar o aplicativo para realizar o processo por threads, porém ainda não consegui criar um pool de conexão para sustentar cada thread executada.
Se alguém souber de alguma dica onde possa encontrar referências sobre o assunto, eu gradeço.
GOSTEI 0
Eniorm
09/06/2008
você tentou fazer algo parecido como explicado no topico acima, de commitar em intervalos de comandos, tipo de 500 a 500?
abs
abs
GOSTEI 0
Cerqueira_r
09/06/2008
Prezado Enio,
Não encontro uma forma de utilizar transações utilizando o Zeos + Postgre. Segue uma parte do código para que vc possa olhar.
Não encontro uma forma de utilizar transações utilizando o Zeos + Postgre. Segue uma parte do código para que vc possa olhar.
// inclui o participante cdsParticipacao.close(); cdsParticipacao.CommandText := ´select * from participacao where codcliente=:codcliente and coddevedor=:coddevedor and num_contrato=:num_contrato and cpfcgc=:cpfcgc´; cdsParticipacao.Params.ParamByName(´codcliente´).AsString := cdsTP1.FieldByName(´codcliente´).AsString; cdsParticipacao.Params.ParamByName(´coddevedor´).AsString := cdsDevAux.FieldByName(´coddevedor´).AsString; cdsParticipacao.Params.ParamByName(´num_contrato´).AsString := F.StrZero(cdsTP1.FieldByName(´num_contrato´).AsString,17); cdsParticipacao.Params.ParamByName(´cpfcgc´).AsString := F.StrZero(cdsTP1.FieldByName(´cpf_cnpj´).AsString,16); cdsParticipacao.Open; if cdsParticipacao.Eof then begin cdsParticipacao.Insert; cdsParticipacao.FieldByName(´codcliente´).Value:=cdsTP1.FieldByName(´codcliente´).AsString; cdsParticipacao.FieldByName(´coddevedor´).Value:=cdsDevAux.FieldByName(´coddevedor´).AsString; cdsParticipacao.FieldByName(´num_contrato´).Value:=F.StrZero(cdsTP1.FieldByName(´num_contrato´).AsString,17); cdsParticipacao.FieldByName(´cpfcgc´).Value:=F.StrZero(cdsTP1.FieldByName(´cpf_cnpj´).AsString,16); cdsParticipacao.FieldByName(´datcadastro´).Value:=Date(); cdsParticipacao.FieldByName(´descricao´).Value:=cdsTP1.FieldByName(´descr_partic´).AsString; cdsParticipacao.FieldByName(´codparticipacao´).Value:=cdsTP1.FieldByName(´cod_participacao´).AsString; cdsParticipacao.Post; cdsParticipacao.ApplyUpdates(1); end;
GOSTEI 0
Diegotiemann
09/06/2008
Na empres aonde trabalho desenvolvemos um exportador e importador que IMPORTA 100.000 registros em 6 minutos.
Isso no firebird, mas atenção:
extensão do banco .FDB não GDB;
Sem nenhuma chave extrangeira e primária;
Pra otimizar o desempenho crie um arquivo do banco com um tamanho grande em disco;
Qualquer coisa meu email diegotiemann@gmail.com
Isso no firebird, mas atenção:
extensão do banco .FDB não GDB;
Sem nenhuma chave extrangeira e primária;
Pra otimizar o desempenho crie um arquivo do banco com um tamanho grande em disco;
Qualquer coisa meu email diegotiemann@gmail.com
GOSTEI 0
Eselvati
09/06/2008
Colega,
Não trabalho com firebird importando arquivos .txt, mas com mysql importo arquivos com 500.000 (quinhentos mil) registros em [b:0ed5588c98]segundos[/b:0ed5588c98] utilizando o comando
load data infile, verifique se nao existe algo semelhante nele...
Ederson Selvati
Não trabalho com firebird importando arquivos .txt, mas com mysql importo arquivos com 500.000 (quinhentos mil) registros em [b:0ed5588c98]segundos[/b:0ed5588c98] utilizando o comando
load data infile, verifique se nao existe algo semelhante nele...
Ederson Selvati
GOSTEI 0
Adriano Santos
09/06/2008
Prezado Enio,
Não encontro uma forma de utilizar transações utilizando o Zeos + Postgre. Segue uma parte do código para que vc possa olhar.
procedure TForm1.Button2Click(Sender: TObject); begin // inclui o participante with cdsParticipacao.Params do begin close; CommandText := ´select * from participacao where codcliente=:codcliente and coddevedor=:coddevedor and num_contrato=:num_contrato and cpfcgc=:cpfcgc´; ParamByName(´codcliente´).AsString := cdsTP1.FieldByName(´codcliente´).AsString; ParamByName(´coddevedor´).AsString := cdsDevAux.FieldByName(´coddevedor´).AsString; ParamByName(´num_contrato´).AsString := F.StrZero(cdsTP1.FieldByName(´num_contrato´).AsString,17); ParamByName(´cpfcgc´).AsString := F.StrZero(cdsTP1.FieldByName(´cpf_cnpj´).AsString,16); Open; if Eof then begin Insert; FieldByName(´codcliente´).Value:=cdsTP1.FieldByName(´codcliente´).AsString; FieldByName(´coddevedor´).Value:=cdsDevAux.FieldByName(´coddevedor´).AsString; FieldByName(´num_contrato´).Value:=F.StrZero(cdsTP1.FieldByName(´num_contrato´).AsString,17); FieldByName(´cpfcgc´).Value:=F.StrZero(cdsTP1.FieldByName(´cpf_cnpj´).AsString,16); FieldByName(´datcadastro´).Value:=Date(); FieldByName(´descricao´).Value:=cdsTP1.FieldByName(´descr_partic´).AsString; FieldByName(´codparticipacao´).Value:=cdsTP1.FieldByName(´cod_participacao´).AsString; Post; ApplyUpdates(1); end; end; end;
Cerqueira, tome cuidado. Seu ApplyUpdates está logo após o Post dentro do Loop? Se estiver, retire-o e coloque depois que o loop terminar. Por que isso? O Post é dado localmente, ou seja, os dados estão sendo gravados no ClientDataSet, na máquina local. Quando executamos um ApplyUpdates, os dados são empacotados e enviados ao servidor. Se estiver fazendo isso a cada Post, sua aplicação ficará lenta, a menos que coloque um contador para que efetue o Apply a cada X registros, exemplo:
...... Inc(Registros); if Registros = 500 then begin ApplyUpdates(1); Regitros := 0; end; .......
[b:d1ed8c84ea]gtts[/b:d1ed8c84ea], mude a rotina e veja se fica mais rápido. Use uma variável do tipo TextFile e importe direto, sem passar por um TStringList. Veja um exemplo
procedure TForm1.Button1Click(Sender: TObject); var Texto : TextFile; Campo1 : string; Campo2 : string; Linha: string; begin AssignFile(Texto, ´C:\Texto.txt´); Reset(Texto); while not EOF(Texto) do begin ReadLn(Texto, Linha); Campo1 := Copy(Linha, 1, 10); Campo2 := Copy(Linha, 11, 10); ListBox1.Items.Add(Campo1 + ´-´ + Campo2); Next; end; CloseFile(Texto); ShowMessage(´Finalizado´); end;
Na empres aonde trabalho desenvolvemos um exportador e importador que IMPORTA 100.000 registros em 6 minutos.
Isso no firebird, mas atenção:
extensão do banco .FDB não GDB;
Sem nenhuma chave extrangeira e primária;
Pra otimizar o desempenho crie um arquivo do banco com um tamanho grande em disco;
Qualquer coisa meu email diegotiemann@gmail.com
Realmente o que o [b:d1ed8c84ea]diegotiemann[/b:d1ed8c84ea] disse tem procedência.
GOSTEI 0