Importação de dados.. .txt para .gdb muito lento.
09/06/2008
0
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
Posts
09/06/2008
Eniorm
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
11/09/2008
Cerqueira_r
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.
11/09/2008
Eniorm
abs
11/09/2008
Cerqueira_r
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;
12/09/2008
Diegotiemann
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
12/09/2008
Eselvati
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
13/09/2008
Adriano Santos
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;
Realmente o que o [b:d1ed8c84ea]diegotiemann[/b:d1ed8c84ea] disse tem procedência.
Clique aqui para fazer login e interagir na Comunidade :)