Newsgroup: it.comp.lang.delphi
Titolo: Come velocizzare ....

Ciao a tutti e ..... buone ferie per chi riesce ad andarci !!!!!
Ho un problema di velocita', mi spego meglio .... devo trovere il modo (se 
esiste) di velocizzare la seguente procedura.
Ho un file di testo dove ogni riga contiene il nome di un comune, il cap, la 
privincia ecc..... il file viene caricato in una TStringList e poi processo 
riga per riga andando a prendere le informazioni necessarie e salvarle in un 
record del DB.
Approssimativamente le righe sono 90000 perche' per i comuni piu' grandi 
sono riportate le frazioni, vie numeri civici ecc..
Ecco come si presenano le righe
"IdCap";"Provincia";"Comune";"Comune2";"Frazione";"Frazione2";"TopoCap";"DugtCap";"NCivico";"CAP"
"66435";"AG";"AGRIGENTO";;"---";;;;;"92100"
"66436";"AG";"AGRIGENTO";;"BORGO LA LOGGIA";;;;;"92100"
"66437";"AG";"AGRIGENTO";;"GIARDINA GALLOTTI";;;;;"92100"
"66438";"AG";"AGRIGENTO";;"MONTAPERTO";;;;;"92100"
"66439";"AG";"AGRIGENTO";;"SAN LEONE MOSE'";;;;;"92100"
"66440";"AG";"AGRIGENTO";;"VILLAGGIO MOSE'";;;;;"92100"
"66441";"AG";"AGRIGENTO";;"VILLASETA";;;;;"92100"
"66442";"AG";"ALESSANDRIA DELLA ROCCA";;"---";;;;;"92010"
Ecco la procedura che risiede nel b7click
procedure TFCAP.BT7Click(Sender: TObject);
Var TL  : TStringList;
    S   : String;
    L   : Byte; // Per la percentuale di avanzamento della progressbar
    I   : Integer;
    UPC : Integer; // Uno per cento
    B   : Double;
begin
  // Cancello tutti i record della tabella
  T.EmptyTable;
  L:=1;
  B:=0;
  Stop:=False;
  PB1.Position:=0;
  PNL4.Visible:=True;
  BT6.Enabled:=False;
  BT7.Enabled:=False;
  TL:=TStringList.Create;
  TL.LoadFromFile('C:\Cap\Cap.Txt');
  UPC:=TL.Count Div 100;
  for I := 1 to TL.Count-1 do // Salto la prima linea perche' e' la legenda
  Begin
    if Stop then Break
    Else
    Begin
      ProcessaLinea(TL.Strings[I]);
      if I=UPC * L then // Chiamo il processmessage solo quando la 
percentuale aumenta di 1
      Begin
        PB1.Position:=PB1.Position+1;
        L:=L+1;
        Application.ProcessMessages;
      End
    End;
  End;
  FreeAndNil(TL);
end;
Procedure TFCAP.ProcessaLinea(S: string);
Var IdCap     : String;
    Provincia : String;
    Comune    : String;
    Comune2   : String;
    Frazione  : String;
    Frazione2 : String;
    TopoCap   : String;
    DugtCap   : String;
    NCivico   : String;
    CAP       : String;
Function RemoveBrakets(S1 : String) : String;
Begin
  while ( (Pos('"',S1)>0) And (S1<>'') ) do Delete(S1,Pos('"',S1),1);
  Result:=S1;
End;
Procedure SalvaRecord;
Begin
  T.Append;
  T.FieldByName('IdCap').AsInteger:=StrToInt(Idcap);
  T.FieldByName('Provincia').AsString:=Provincia;
  T.FieldByName('Comune').AsString:=Comune;
  T.FieldByName('Comune2').AsString:=Comune2;
  T.FieldByName('Frazione').AsString:=Frazione;
  T.FieldByName('Frazione2').AsString:=Frazione2;
  T.FieldByName('TopoCap').AsString:=TopoCap;
  T.FieldByName('DugtCap').AsString:=DugtCap;
  T.FieldByName('NCivico').AsString:=NCivico;
  T.FieldByName('Cap').AsString:=Cap;
  T.Post;
End;
begin
  if Pos(';',S)>0 then
  Begin
    // IdCap
    IdCap:=RemoveBrakets(Copy(S,1,Pos(';',S)-1));
    Delete(S,1,Pos(';',S));
    // Provincia
    Provincia:=RemoveBrakets(Copy(S,1,Pos(';',S)-1));
    Delete(S,1,Pos(';',S));
    // Comune
    Comune:=RemoveBrakets(Copy(S,1,Pos(';',S)-1));
    Delete(S,1,Pos(';',S));
    // Comune2
    Comune2:=RemoveBrakets(Copy(S,1,Pos(';',S)-1));
    Delete(S,1,Pos(';',S));
    // Frazione
    Frazione:=RemoveBrakets(Copy(S,1,Pos(';',S)-1));
    if Frazione='---' then Frazione:='';
    Delete(S,1,Pos(';',S));
    // Frazione2
    Frazione2:=RemoveBrakets(Copy(S,1,Pos(';',S)-1));
    Delete(S,1,Pos(';',S));
    // TopoCap
    TopoCap:=RemoveBrakets(Copy(S,1,Pos(';',S)-1));
    Delete(S,1,Pos(';',S));
    // DugtCap
    DugtCap:=RemoveBrakets(Copy(S,1,Pos(';',S)-1));
    Delete(S,1,Pos(';',S));
    // NCivico
    NCivico:=RemoveBrakets(Copy(S,1,Pos(';',S)-1));
    Delete(S,1,Pos(';',S));
    // Cap
    Cap:=RemoveBrakets(S);
    SalvaRecord;
  End;
end;
Pre processare queste 90000 rughe impiega una montagna di tempo (per esempio 
anche piu' di 20 minuti).
Ho provato quasi tutto ...... anche cercando di utilizzare le funzioni di 
fastcode (che pero' non ho trovato per delhi 2010).
Il tutto rallenta nel SalvaRecord, se commento con (*  *) tutta la procedura 
il tutto si riduce a 2-3 secondi ..... quindi il problema risiede nella 
procedura di update del DB (con o senza file indice).
Qualche idea ??
Windows XP SP 3
Delphi 2010
TurboDB 5.20
Grazie a tutti
Ciao, Daniele
__________ Information from ESET NOD32 Antivirus, version of virus signature database 5335 (20100802) __________
The message was checked by ESET NOD32 Antivirus.
http://www.eset.com

 TurboDB 5.20
Oracle Express
:-))))
-- 
http://www.kiva.org
Per il ng it.comp.lang.delphi: astenersi perditempo e lamer.
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it


A parte che D2010 č un ottimo strumento e al .Net continuo a preferire 
dieci volte il codice nativo, una cosa č vera se la lentezza sta nel 
procedimento di update del db conviene provare un altro motore db. 
Consiglio SQLLite, MyLittleBase, Access oppure i server MySql (meglio 
Postgresql per il fatto che č potente tanto quanto ma completamente 
gratuito) e prova le Zeoslib (per D2010 ci sono le 7 in versione alpha) 
e anche il SQLServer express o l'Oracle Express.
-- 
Il silenzio ti fa vedere ciň che il rumore non ti fa cogliere ..


se l'inserimento riga per riga è troppo lento
si può provare l'inserimento batch
creando un file in un formato riconosciuto dal db
e importando direttamente quello
non conosco TurboDB, se è quello di dataweb
sembra ci sia il componente TTdbBatchMove
per importare file in formato testo

 "66435";"AG";"AGRIGENTO";;"---";;;;;"92100"
questo e' un file csv, non so se risolve/aiuta il tuo problema, pero' 
esistono componenti gia' pronti per fare il 90% del lavoro di lettura 
che fai tu.
Ad esempio il tjvCsvDataSet delle Jedi
-- 
=============================================================
Alberto Rubinelli - Fondazione "Museo del computer"
Via Costantino Perazzi 22 - 28100 NOVARA - ITALY
Tel 0321 1856032   Fax 0321 391769   BBS 0321 392320
Mail: 
alb...@oldcomputers.de
Sito internet : 
http://www.museodelcomputer.org
=============================================================

 procedura di update del DB (con o senza file indice).
ciao.
Non e' che ci sia molto da fare, se il problema e' la scrittura
sul DB devi cambiare DB (o driver di accesso) o ti tieni i tempi! :-)
Una piccola riduzione di tempo la puoi ottenere sostituendo
la chiamata a fieldByName(), che e' un po' costosa e inutile
perche' fa la ricerca dello stesso campo 90.000 volte. Ti
conviene farla una volta sola prima del loop
Anche assegnare la proprieta' Value al posto di AsInteger AsString
eccetera dovrebbe essere leggermente piu' veloce.
Qualcosa del genere:
procedure ProcessaFile( filename : string );
var
  TIdCap, TProvincia, ... : TField;
  procedure SalvaRecord;
  begin
    T.Append;
    TIdCap.Value := StrToInt(Idcap);
    TProvincia.Value :=Provincia;
  ...
  end;
begin
  TIdCap     := T.FieldByName( 'IdCap' );
  TProvincia := T.FieldByName( 'Provincia' );
  // Loop
end;
ciao
Giacomo
PS. Mettere tutta la logica nell'evento OnClick e' considerato
cattiva pratica: metti tutto in una procedure a parte e dentro
al click metti solo il codice che chiama la procedura.

 Il tutto rallenta nel SalvaRecord, se commento con (*  *) tutta la procedura
Disabilita griglie e componenti DBaware se presenti, cambia tipo di 
connessione al DB, fai un test con un altro DB...
G.
-- 
Ibis et redibis non morieris in bello
http://goblinland.myminicity.com/

 record del DB.
[cut all]
a) se hai un problema di performance come prima cosa dovresti
individuare qual è il collo di bottiglia misurando la percentuale di
tempo delle varie operazioni (v. getTickCount o qualcosa di simile)
b) TStringList ha la proprietà capacity. Impostala prima di caricare
il file
c) TStringList ha la proprietà delimitedText: istanzia un'altra sl,
che userai per ciclare sulle righe di quella in cui hai caricato il
file:
   for line := 1 to pred(slFile.count) do begin
      slRow.delimitedText := slFile[line];  // splitta la riga nei
campi
      for i := 0 to pred(slRow.count) do begin
         setFieldValue(i, slRow[i]);   // setFieldValue da
implementare :-)
      end;
   end;
Saluti
Paolo Arosio

1) non so se turbodb e' fileserver o client/server.
Se e' un client/server, butta via table e usa una query
2) la processmessages rallenta in modo mostruoso.
Fai in modo che venga fatta ogni 100 iterazioni.
Se vuoi la progressbar aggiornata ad ogni incremento di 1 in
petcentuale usa repaint.
3) usa nomi significativi. Leggere quel codice mi ha fatto venire un
attacco di ulcera
A.

 dieci volte il codice nativo
Mah, piano piano sto passando al Visual C#. Mi rimane la voglia di provare
Delphi Prims, ma tutto l'amdaradan Embarcadero nell'arco dei dodici mesi
lo abbandonero' definitivamente.


Ciao a tutti,
     grazie per le numerose risposte !!!
Rispondo qui cercando di non tralasciare nessuno.
Lo spezzone di codice riportato fa parte di una form, e questa form ha due 
CreateNew diversi, uno se il db dei cap esiste (quindi qualcuno ha importato 
i dati) e una nel caso il db non esiste (quindi si deve importare il tutto).
Mi sono accorto che nella form ho messo un TDataSource il cui il suo DataSet 
puntava alla tabella da riempire.
Ho eliminato il TDataSource e il tutto si e' velocizzato in modo esagerato, 
ora per importare le 90000 righe ( e non rughe ) impiega 5 secondi.
La stessa operazione fatta con il batchmove ne richiede qualcuno in piu'.
Resto dubbioso che sia stato sufficiente rimuovere un componente per 
migliorare di cosi' tanto le prestazioni!!!!
Il processmessage serve perche' c'e' un bottoncino che permette all'utente 
di fermare l'importazione .... anche se questo significa perdere tutti 
record !!!
Il codice propsto e' stato in parte cambiato, la procedura e' stata portata 
fuori dall'evento onclick e ...... ok devo dare dei nomi piu' sensati alle 
variabili !!!
Adesso riavvio il sistema .....
Magari poi torna una tartaruga !!!
Grazie
Ciao, Daniele
__________ Information from ESET NOD32 Antivirus, version of virus signature database 5338 (20100803) __________


 fuori dall'evento onclick e ......
cioe'...?
A.

 migliorare di cosi' tanto le prestazioni!!!!
Infatti e' cosi': c'e' di certo qualcosa in piu' che non hai
considerato! :)
magari il datasource era collegato a una DBGrid o ad altri controlli?
In questo caso ogni inserimento nel dataset comporta un ridisegno
della
grafica dei controlli, che e' un'operazione piuttosto costosa.
Altrimenti potresti aver messo del codice nell'evento OnChange
del datasource? In questo caso quel codice viene eseguito per
ogni modifica ad ogni campo del dataset.
In genere quando si fanno operazioni sui dataset e' consigliabile
proprio per evitare questi due problemi usare Disable/EnableControls:
T.DisableControls;
try
  // inserisci 90000 righe su T
  // ...
finally
  T.EnableControls;
end;
ciao
Giacomo

 cioe'...?
Avevo messo la logica nell'onclick, quindi risultava un onclick con diverse 
linee, ho messo la logica nella procedura x e nell'onclick ho chiamto x 
(andava fatto subito ....)
Grazie
Ciao, Daniele 
__________ Information from ESET NOD32 Antivirus, version of virus signature database 5348 (20100806) __________



In bocca al lupo. Io con il C# ne ho passate di tutti i colori, è un po 
come dire: abbandono tutto e vado su Java ... bhè auguri. Dipende molto 
dall'uso che se ne fa comunque.
-- 
Il silenzio ti fa vedere ciò che il rumore non ti fa cogliere ..