Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Insert-Schleife viel zu langsam (https://www.delphipraxis.net/164838-insert-schleife-viel-zu-langsam.html)

Partikelecho 2. Dez 2011 07:20

Datenbank: DBISAM • Version: 4 • Zugriff über: DBISAMQuery

Insert-Schleife viel zu langsam
 
Guten Morgen,
Ich bin neu hier, also verzeiht mir eventuell falsch genutzte Foren, o.ä. fürs Erste.

Meine Aufgabe ist das Programmieren einer Anwendung zum Auslesen von Ordnern (welche immer eine Datenbank sind, also Pfad = Datenbank) und das darstellen der Dateiinformationen in einem DBGrid.

Ich verwende Delphi 6 und soweit ich weiß DBISAM 4 (kann ich im moment nicht überprüfen).
Mein Problem ist, dass zwar die FindAllFiles-Funktion und die Variablenzuweisung in der Schleife relativ schnell gehen, das Inserten von 40.000 Datensätzen in etwa 8 bis 10 Minuten dauert.

- Version mit Parametern statt direkter Variablenübergabe ist noch langsamer
- Bulkinsert von jeweils 50, 100 oder 1000 SQL-Inserts dauert in etwa genau so langsam.
- Die Funktionen GetFileTimes & GetFileSize laufen auch nur ein paar Sekunden.
- Kommentiere ich den SQL-Teil ab with aus, so dauert es ebenfalls nur ca. 10 Sekunden (gut, immernoch zu lange, aber im Vergleich zu Minuten..)
- SL[i] (eine Stringlist) enthält die einzufügenden Dateien.

Delphi-Quellcode:
procedure TFRM_Main.ReadInInvA;
var
  i, invasize:Integer;
  inva, invaaccessed, invacreated, invamodified:String;
  created, accessed, modified:TDateTime;
begin
  QRY_Container.SQL.Clear;
  inva := invaname;
  for i := 0 to SL.Count-1 do
  begin
    if GetFileTimes(CXBE_DbDir.Text+’\‘SL[i], created, accessed, modified) then
    begin
      invaaccessed := DateTimeToStr(accessed);
      invacreated := DateTimeToStr(created);
      invamodified := DateTimeToStr(modified);
    end;
    invasize := GetFileSize(CXBE_DbDir.Text’\‘+SL[i]);
    with QRY_Container do
    begin
      SQL.Add(’INSERT INTO ‘inva’(INVA_FILE, INVA_FILE_CREATED,‘+
              ’INVA_FILE_ALTERED, INVA_FILE_VIEWED, INVA_FILE_SIZE) VALUES’+
              ’ (’’’+SL[i]‘’’,‘’’invacreated+’’’,‘+
              ’’’’+invamodified+’’’,’’’+invaaccessed+’’’,‘inttostr(invasize)’);’);
      if i > 0 then
      begin
        if (i mod 1000) = 0 then
        begin
          ExecSQL;
          SQL.Clear;
        end;
      end;
      if i = SL.Count-1 then
      ExecSQL;
      // 1000 Insert-Befehle werden hintereinander geschrieben und dann zusammen ausgeführt.
    end;
  end;
end;

Bernhard Geyer 2. Dez 2011 07:44

AW: Insert-Schleife viel zu langsam
 
Prepared Statements mit Parameter sollten schneller sein.
DBISAM ist eine Destkop-Datenbank. Hier solltest du deinen Virenscanner so einstellen das die enstprechenden DB-Dateien nicht untersucht weden.

Wie viele Indizes gibt es auf deiner Tabelle. Je mehr desto langsamer ist auch ein Insert. Hier bremst im gegensatz zu Abfragen jeder Index.

tankard 2. Dez 2011 08:28

AW: Insert-Schleife viel zu langsam
 
hi,

also so kann das nur langsam sein.
da bei jedem insert die daten direkt auf platte geschrieben werden.
schau mal ob das datenbanksystem auch transactions kann. mal nach googlen was das ist. http://www.firstsql.com/tutor5.htm

gruss
tankard

ps: nur weil du 1000 sql statements zusammenfuegst, werden diese doch der reihe nach abgearbeitet, insert befehle ohne transaction, werden direkt auf platte geschrieben. daher hast du bei 1000 inserts, 1000 plattenzugriffe. wenn du tranaktionen nutzt, wird nach einem commit nur einmal alles weggeschrieben.

Medium 2. Dez 2011 09:03

AW: Insert-Schleife viel zu langsam
 
Es ist auch erheblich schneller, mehrere Sätze in einem Insert zu machen:
Code:
INSERT INTO foo VALUES (bar1, peng1), (bar2, peng2), (bar3, ...
Wie viele Sätze man in so ein Statement hängen kann, hängt vom DBMS ab (bzw. ist spätestens nach 2GB wegen Stringlänge Ende ;)), aber ich hab mit 100 am Stück zumindest noch nie Probleme bekommen, und die reichten mir bislang für einen deftigen boost.

Partikelecho 7. Dez 2011 06:49

AW: Insert-Schleife viel zu langsam
 
Hallo,
Ich hab nun endlich wieder Zugriff auf meine Source gehabt und wollte euch noch zeigen, wie ich die Zeit massiv verkürzen konnte, in der die Dateien eingelesen werden.

tankards Vorschlag mit Transactions zu arbeiten war zielführend.
Zusätzlich habe ich den Insertpart durch AppendRecord ersetzt.
Falls ihr noch Verbesserungsvorschläge habt, wie ich die Zeit weiter verkürzen könnte, dann immer her damit.

Danke für eure Hilfe..

Delphi-Quellcode:
procedure TFRM_Main.ReadInInvA;
var
  i, invasize:Integer;
  invaaccessed, invacreated, invamodified:String;
  created, accessed, modified:TDateTime;
begin
  DB_Container.Directory := CXBE_InvDir.Text;
  DB_Container.Open;
  TBL_Container.DatabaseName := DB_Container.DatabaseName;
  DB_Container.StartTransaction;
  for i := 0 to SL.Count-1 do
  begin
    if GetFileTimes(CXBE_DbDir.Text+’\‘+SL[i], created, accessed, modified) then
    begin
      invaaccessed := DateTimeToStr(accessed);
      invacreated := DateTimeToStr(created);
      invamodified := DateTimeToStr(modified);
    end;
    invasize := GetFileSize(CXBE_DbDir.Text+’\’+SL[i]);
    with TBL_Container do
    begin
      DatabaseName := DB_Container.DatabaseName;
      TableName := invaname;
      Open;
      AppendRecord([null, SL[i], invacreated, invamodified, invaaccessed, invasize]);
      Close;
    end;
  end;
  DB_Container.Commit;
  DB_Container.Close;
end;

himitsu 7. Dez 2011 07:03

AW: Insert-Schleife viel zu langsam
 
Zitat:

Delphi-Quellcode:
      DatabaseName := DB_Container.DatabaseName;
      TableName := invaname;
      Open;
      ...
      Close;

Diese Teile ändern sich nicht.
Wieso also nicht einfach nur einmal for/nach der For-Schleife?

Statt der vielen FileTime- und FileSize-Funktionen könnte man es mal mit einem MSDN-Library durchsuchenFindFirstFile versuchen. (das ganze Geraffel vom Delphi-Referenz durchsuchenFindFirst kann man sich hier sparen)


PS: SL ist eine sehr gut benamte externe Variable. :thumb:

Partikelecho 7. Dez 2011 07:11

AW: Insert-Schleife viel zu langsam
 
Zitat:

Zitat von himitsu (Beitrag 1139928)
Zitat:

Delphi-Quellcode:
      DatabaseName := DB_Container.DatabaseName;
      TableName := invaname;
      Open;
      ...
      Close;

Diese Teile ändern sich nicht.
Wieso also nicht einfach nur einmal for/nach der For-Schleife?

Aber hat dieser Teil dann nicht nur die Werte des letzten Schleifendurchlaufs? Es werden doch immer jeweils die Variablen neu erstellt und für jede Datei neu hinzugefügt.

Zitat:

Zitat von himitsu (Beitrag 1139928)
Statt der vielen FileTime- und FileSize-Funktionen könnte man es mal mit einem MSDN-Library durchsuchenFindFirstFile versuchen. (das ganze Geraffel vom Delphi-Referenz durchsuchenFindFirst kann man sich hier sparen)


PS: SL ist eine sehr gut benamte externe Variable. :thumb:

Damit werde ich mich noch auseinandersetzen, ich hatte ohnehin vor, diese Funktionen noch anzupassen/ zu verbessern.

Naja gut, SL wird in dem Programm immer mal wieder verwendet, es hat einen allgemeinen Zweck und wird nicht stetig gebraucht. Deswegen ist der Bezeichner SL so geblieben. ;)

himitsu 7. Dez 2011 07:23

AW: Insert-Schleife viel zu langsam
 
AppendRecord macht
Delphi-Quellcode:
Append;
// Felder setzen
Post;
und das geht doch wohl auch mehrmals hintereinande, ohne jedesmal die Tabelle neu auf+zu zumachen?

Eventuell auch noch ein DisableControls/EnableControls drumrum.


Zitat:

Naja gut, SL wird in dem Programm immer mal wieder verwendet, es hat einen allgemeinen Zweck und wird nicht stetig gebraucht. Deswegen ist der Bezeichner SL so geblieben.
Also eine unbestimmte globale Variable, bei der man nie genau weiß, was sich nun gerade dort drin befindet? :stupid:

Sir Rufo 7. Dez 2011 08:29

AW: Insert-Schleife viel zu langsam
 
Zitat:

Zitat von himitsu (Beitrag 1139934)
Zitat:

Naja gut, SL wird in dem Programm immer mal wieder verwendet, es hat einen allgemeinen Zweck und wird nicht stetig gebraucht. Deswegen ist der Bezeichner SL so geblieben.
Also eine unbestimmte globale Variable, bei der man nie genau weiß, was sich nun gerade dort drin befindet? :stupid:

Hierbei handelt es sich um das StringLuder. Da darf jeder mal ran und was reinstecken und man weiß eigentlich nie, was man so richtig bekommt, aber meistens geht hoffentlich alles gut. :mrgreen:

DeddyH 7. Dez 2011 08:30

AW: Insert-Schleife viel zu langsam
 
[OT] Ich dachte, das hieße Santa Laus :mrgreen: [/OT]


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:43 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz