AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Delphi Insert-Schleife viel zu langsam
Thema durchsuchen
Ansicht
Themen-Optionen

Insert-Schleife viel zu langsam

Ein Thema von Partikelecho · begonnen am 2. Dez 2011 · letzter Beitrag vom 10. Dez 2011
Antwort Antwort
Partikelecho

Registriert seit: 2. Dez 2011
14 Beiträge
 
Delphi 6 Enterprise
 
#1

Insert-Schleife viel zu langsam

  Alt 2. Dez 2011, 08:20
Datenbank: DBISAM • Version: 4 • Zugriff über: DBISAMQuery
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;
  Mit Zitat antworten Zitat
Benutzerbild von Bernhard Geyer
Bernhard Geyer

Registriert seit: 13. Aug 2002
17.213 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Insert-Schleife viel zu langsam

  Alt 2. Dez 2011, 08:44
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.
Windows Vista - Eine neue Erfahrung in Fehlern.
  Mit Zitat antworten Zitat
tankard

Registriert seit: 5. Mai 2006
2 Beiträge
 
#3

AW: Insert-Schleife viel zu langsam

  Alt 2. Dez 2011, 09:28
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.
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.687 Beiträge
 
Delphi 2007 Enterprise
 
#4

AW: Insert-Schleife viel zu langsam

  Alt 2. Dez 2011, 10:03
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.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Partikelecho

Registriert seit: 2. Dez 2011
14 Beiträge
 
Delphi 6 Enterprise
 
#5

AW: Insert-Schleife viel zu langsam

  Alt 7. Dez 2011, 07:49
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;

Geändert von Partikelecho ( 7. Dez 2011 um 08:03 Uhr) Grund: Code-Tag gefixt
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.326 Beiträge
 
Delphi 12 Athens
 
#6

AW: Insert-Schleife viel zu langsam

  Alt 7. Dez 2011, 08:03
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.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:17 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz