Entwickler-Ecke
Datenbanken - Warum so langsam?
D. Annies - Di 07.07.09 20:13
Titel: Warum so langsam?
Hi, Delpher,
warum ist der folgende Code, durch den eine Merge-Datei entsteht, so langsam - ca. 2 sec pro Datensatz??
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143:
| procedure TForm1.Button28Click(Sender: TObject); var InputString : string; begin InputString := 'merge.dbf'; Inputstring := InputBox('Merge-Filename', 'Dateiname:', Inputstring); with form2.table1 do begin Active := False; TableName := Inputstring; TableType := ttDefault; FieldDefs.Clear; FieldDefs.Add('Name', ftString, 25, False); FieldDefs.Add('Vorname', ftString, 25, False); FieldDefs.Add('Klasse', ftString, 5, False); FieldDefs.Add('Geschlecht', ftString, 1, False); FieldDefs.Add('Gebdat', ftString, 10, False); FieldDefs.Add('Punkte', ftinteger); CreateTable; end; form2.table1.active := true;
table1.Close; table1.TableName := concat(home, '\', 'R1x.dbf'); table1.active := true; table1.First; while not table1.Eof do begin form2.Table1.Append; form2.Table1.fieldbyname('NAME').asstring := table1.fieldbyname('NAME').asstring; form2.Table1.fieldbyname('VORNAME').asstring := table1.fieldbyname('VORNAME').asstring; form2.Table1.fieldbyname('KLASSE').asstring := table1.fieldbyname('KLASSE').asstring; form2.Table1.fieldbyname('GESCHLECHT').asstring := table1.fieldbyname('Geschlecht').asstring; form2.Table1.fieldbyname('GEBDAT').asstring := table1.fieldbyname('gebdat').asstring; form2.Table1.fieldbyname('PUNKTE').asinteger := table1.fieldbyname('Punkte').asinteger; form2.table1.Post; table1.Next; end; showmessage('merge '+ table1.TableName + ' ok'); table3.Close; table3.TableName := concat(home, '\', 'R7x.dbf'); table3.active := true; table3.First; while not table3.Eof do begin form2.Table1.Append; form2.Table1.fieldbyname('NAME').asstring := table3.fieldbyname('NAME').asstring; form2.Table1.fieldbyname('VORNAME').asstring := table3.fieldbyname('VORNAME').asstring; form2.Table1.fieldbyname('KLASSE').asstring := table3.fieldbyname('KLASSE').asstring; form2.Table1.fieldbyname('GESCHLECHT').asstring := table3.fieldbyname('Geschlecht').asstring; form2.Table1.fieldbyname('GEBDAT').asstring := table3.fieldbyname('gebdat').asstring; form2.Table1.fieldbyname('PUNKTE').asinteger := table3.fieldbyname('Punkte').asinteger; form2.table1.Post; table3.Next; end; showmessage('merge '+ table3.TableName + ' ok'); table4.Close; table4.TableName := concat(home, '\', 'R8x.dbf'); table4.active := true; table4.First; while not table4.Eof do begin form2.Table1.Append; form2.Table1.fieldbyname('NAME').asstring := table4.fieldbyname('NAME').asstring; form2.Table1.fieldbyname('VORNAME').asstring := table4.fieldbyname('VORNAME').asstring; form2.Table1.fieldbyname('KLASSE').asstring := table4.fieldbyname('KLASSE').asstring; form2.Table1.fieldbyname('GESCHLECHT').asstring := table4.fieldbyname('Geschlecht').asstring; form2.Table1.fieldbyname('GEBDAT').asstring := table4.fieldbyname('gebdat').asstring; form2.Table1.fieldbyname('PUNKTE').asinteger := table4.fieldbyname('Punkte').asinteger; form2.table1.Post; table4.Next; end; showmessage('merge '+ table4.TableName + ' ok'); table5.Close; table5.TableName := concat(home, '\', 'R9x.dbf'); table5.active := true; table5.First; while not table5.Eof do begin form2.Table1.Append; form2.Table1.fieldbyname('NAME').asstring := table5.fieldbyname('NAME').asstring; form2.Table1.fieldbyname('VORNAME').asstring := table5.fieldbyname('VORNAME').asstring; form2.Table1.fieldbyname('KLASSE').asstring := table5.fieldbyname('KLASSE').asstring; form2.Table1.fieldbyname('GESCHLECHT').asstring := table5.fieldbyname('Geschlecht').asstring; form2.Table1.fieldbyname('GEBDAT').asstring := table5.fieldbyname('gebdat').asstring; form2.Table1.fieldbyname('PUNKTE').asinteger := table5.fieldbyname('Punkte').asinteger; form2.table1.Post; table5.Next; end; showmessage('merge '+ table5.TableName + ' ok'); table6.Close; table6.TableName := concat(home, '\', 'R5x.dbf'); table6.active := true; table6.First; while not table6.Eof do begin form2.Table1.Append; form2.Table1.fieldbyname('NAME').asstring := table6.fieldbyname('NAME').asstring; form2.Table1.fieldbyname('VORNAME').asstring := table6.fieldbyname('VORNAME').asstring; form2.Table1.fieldbyname('KLASSE').asstring := table6.fieldbyname('KLASSE').asstring; form2.Table1.fieldbyname('GESCHLECHT').asstring := table6.fieldbyname('Geschlecht').asstring; form2.Table1.fieldbyname('GEBDAT').asstring := table6.fieldbyname('gebdat').asstring; form2.Table1.fieldbyname('PUNKTE').asinteger := table6.fieldbyname('Punkte').asinteger; form2.table1.Post; table6.Next; end; showmessage('merge '+ table6.TableName + ' ok'); table7.Close; table7.TableName := concat(home, '\', 'R6x.dbf'); table7.active := true; table7.First; while not table7.Eof do begin form2.Table1.Append; form2.Table1.fieldbyname('NAME').asstring := table7.fieldbyname('NAME').asstring; form2.Table1.fieldbyname('VORNAME').asstring := table7.fieldbyname('VORNAME').asstring; form2.Table1.fieldbyname('KLASSE').asstring := table7.fieldbyname('KLASSE').asstring; form2.Table1.fieldbyname('GESCHLECHT').asstring := table7.fieldbyname('Geschlecht').asstring; form2.Table1.fieldbyname('GEBDAT').asstring := table7.fieldbyname('gebdat').asstring; form2.Table1.fieldbyname('PUNKTE').asinteger := table7.fieldbyname('Punkte').asinteger; form2.table1.Post; table7.Next; end; showmessage('merge '+ table7.TableName + ' ok'); table8.Close; table8.TableName := concat(home, '\', 'RDx.dbf'); table8.active := true; table8.First; while not table8.Eof do begin form2.Table1.Append; form2.Table1.fieldbyname('NAME').asstring := table8.fieldbyname('NAME').asstring; form2.Table1.fieldbyname('VORNAME').asstring := table8.fieldbyname('VORNAME').asstring; form2.Table1.fieldbyname('KLASSE').asstring := table8.fieldbyname('KLASSE').asstring; form2.Table1.fieldbyname('GESCHLECHT').asstring := table8.fieldbyname('Geschlecht').asstring; form2.Table1.fieldbyname('GEBDAT').asstring := table8.fieldbyname('gebdat').asstring; form2.Table1.fieldbyname('PUNKTE').asinteger := table8.fieldbyname('Punkte').asinteger; form2.table1.Post; table8.Next; end; showmessage('merge '+ table8.TableName + ' ok'); label21.Caption := inputstring; showmessage('MergeFile wurde erzeugt'); end; |
Da bin ich mal gespannt auf eure Antworten,
Detlef
Niko S. - Di 07.07.09 20:16
sind diese tables sichtbare objekte? wenn ja mach die mal unsichtbar meistens ist das denn viel schneller..
Regan - Di 07.07.09 20:26
Kann es sein, dass das asstring sehr lange dauert? Ich habe zwar von dieser Datenbankart keine Ahnung, aber Strings umwandeln dauert ja an sich schon lange.
Sinspin - Di 07.07.09 20:27
Niko S. hat folgendes geschrieben : |
sind diese tables sichtbare objekte? wenn ja mach die mal unsichtbar meistens ist das denn viel schneller.. |
Joa, dem schließe ich mich an!
Man kann mit einem Aufruf Table.DisableControls dafür sorgen das eine Tabelle keine Ereignisse mehr von sich gibt wenn sich an ihr was ändert, also bei Datensatzwechsel oder so. Mit EnableControls musst du das dann aber wieder anschalten wenn du fertig bist.
Statt den Zweisungen via AsString kannst du es auch mal mit Value probieren. (
FieldByName('xxx').Value := FieldByName('xxx').Value) So müssten sich eigentlich ein paar Sekunden über die gesammten Daten rausschlagen lassen.
jasocul - Mi 08.07.09 09:32
Über wieviel Datensätze reden wir denn hier?
Offensichtlich setzt du auch noch die BDE ein. Mach mal zwischendurch ein FlushBuffers. Wenn ich mich richtig erinnere, wird sonst alles "irgendwo" zwischengespeichert, bis die Datenbank genug Zeit hat, dass wirklich zu speichern.
Es gibt noch weiteres Optimierungspotential:
- AsString rausschmeißen.
- Statt FieldByName über Fields[FeldIndex] zugreifen
D. Annies - Mi 08.07.09 16:09
Danke für eure Ideen.
Aber da es nur ca. 900 DS waren, konnten diese Tuningmöglichkeiten nicht so viel bringen. Ich habe ganz "einfach" eine neue Table genommen, und dann ging's, also, in der obigen Lesart table3 statt table2.
Grüße aus Lübeck,
Detlef
Bergmann89 - Do 09.07.09 00:58
Hey,
nur ma so nebenbei, warum hast dir nich ne extra Funktion gemacht, die die daten kopiert. Weil du machst ja 7ma das gleiche un wenn du was ändern musst, änderst du das dann 7ma. das is irgendwie umständlich...
Mfg Bergmann.
D. Annies - Do 09.07.09 13:23
hast völlig recht, das mach ich als nächstes, eine schöne Proc mit Übergabeparameter.
Danke, Detlef
alzaimar - Do 09.07.09 20:14
Übrigens: "FieldByName" sucht jedesmal das entsprechende Feld aus der Feldliste (mit einfacher For-Schleife).
Bei 900 Records ist das nicht so wild, aber grundsätzlich sollte man vor so einer Schleife seine Felder einmalig suchen und in einer lokalen 'TField'-Variablen speichern. Dann geht das nochmals schneller.
D. Annies - Do 09.07.09 20:36
Hm, alzi, hast du mal ein Beispiel?
(vielleicht adaptiert von oben)
Detlef
alzaimar - Fr 10.07.09 08:23
D. Annies hat folgendes geschrieben : |
Hm, alzi, hast du mal ein Beispiel? |
Klar, Deti :lol:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| procedure TForm1.Button28Click(Sender: TObject); var InputString : string; fld1Name, fld1Vorname, fld1Klasse, fld1Geschlecht, fld1Datum, fld1Punkte, fld2Name, fld2Vorname, fld2Klasse, fld2Geschlecht, fld2Datum, fld2Punkte : TField;
begin ... table1.active := true; table1.First; fld1Name := form2.Table1.fieldbyname('NAME'); fld1Vorname := form2.Table1.fieldbyname('VORNAME'); ... fld2Name := Table2.fieldbyname('NAME'); fld2Vorname := Table2.fieldbyname('VORNAME'); ... while not table1.Eof do begin form2.Table1.Append; fld1Name.Value := fld2Name.Value; fld1Vorname.Value := fld2Vorname.Value; ... form2.table1.Post; table1.Next; end; showmessage('merge '+ table1.TableName + ' ok'); ... end; |
Oder gleich noch kompakter:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54:
| Function CreateStringListFromCommaString (aCommaText : String) : TStringList; Begin Result := TStringList.Create; Result.Delimiter := ','; Result.DelimitedText := aFieldNames; End;
Procedure CopyTables (aTblName : String; aSrc, aDst : TTable, aFieldnames : String); Var srcFields, dstFields : Array Of TField; i, fieldCount : Integer; slFieldNames : TStringList;
Begin aSrc.Close; aSrc.TableName := concat(home, '\', aTblName); aSrc.active := true; slFieldNames := CreateStringListFromCommaString(aFieldNames); Try setLength (srcFields, slFieldNames.Count); setLength (dstFields, slFieldNames.Count); fieldCount := Length (Fieldnames); For i := 0 to FieldCount - 1 do begin srcFields[i] := aSrc.FieldByname(slFieldnames[i]); dstFields[i] := aDst.FieldByname(slFieldnames[i]); End; Finally slFieldNames.Free; End; aSrc.First; while not aSrc.Eof do Begin aDst.Append; For i := 0 do FieldCount - 1 do dstFields[i].Value := SrcFields[i].Value; aDst.Post; aSrc.Next; End; showmessage('merge '+ aSrc.TableName + ' ok'); End;
procedure TForm1.Button28Click(Sender: TObject); var InputString : string;
begin CopyTables ('R1x.dbf',table1, form2.Table1, 'Name,Vorname,Klasse,Geschlecht,GebDat,Punkte'); CopyTables ('R7x.dbf',table3, form2.Table1, 'Name,Vorname,Klasse,Geschlecht,GebDat,Punkte'); CopyTables ('R8x.dbf',table4, form2.Table1, 'Name,Vorname,Klasse,Geschlecht,GebDat,Punkte'); CopyTables ('R9x.dbf',table5, form2.Table1, 'Name,Vorname,Klasse,Geschlecht,GebDat,Punkte'); CopyTables ('R5x.dbf',table6, form2.Table1, 'Name,Vorname,Klasse,Geschlecht,GebDat,Punkte'); CopyTables ('R6x.dbf',table7, form2.Table1, 'Name,Vorname,Klasse,Geschlecht,GebDat,Punkte'); CopyTables ('Rdx.dbf',table8, form2.Table1, 'Name,Vorname,Klasse,Geschlecht,GebDat,Punkte'); showmessage('MergeFile wurde erzeugt'); end; |
Ungetestet.
D. Annies - Fr 10.07.09 19:41
Hi, alzi,
Donnerwetter! Da kann ich was mit anfangen!
Einige Kleinigkeiten habe ich schon beseitigt.
Noch stört die Fehlermeldung: Undefinierter Bezeichner 'afieldnames'
Delphi-Quelltext
1:
| Result.DelimitedText := aFieldNames; |
Bis wann?
Deti :D :D :D
alzaimar - Fr 10.07.09 20:05
Oh, sch**** Copy & Paste.
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| Function CreateStringListFromCommaString (aCommaText : String) : TStringList; Begin Result := TStringList.Create; Result.Delimiter := ','; Result.DelimitedText := aCommaText; End; |
D. Annies - Fr 10.07.09 20:15
Wow, danke für deine prompte Antwort.
D. Annies - Fr 10.07.09 20:24
Einen "kleinen" hab ich noch zur Laufzeit:
Listenindex überschreitet das Maximum(6)
Wasndas?
alzaimar - Fr 10.07.09 20:56
D. Annies hat folgendes geschrieben : |
Listenindex überschreitet das Maximum(6)
Wasndas? |
Das nennt sich 'Runtime-Error' bzw. Laufzeitfehler. Wieso fragst Du?
Ach, liegt an dem Müll, den ich zusammengetippselt habe...
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| Procedure CopyTables (aTblName : String; aSrc, aDst : TTable; aFieldnames : String); Var srcFields, dstFields : Array Of TField; i : Integer; slFieldNames : TStringList;
Begin aSrc.Close; aSrc.TableName := concat(home, '\', aTblName); aSrc.active := true; slFieldNames := CreateStringListFromCommaString(aFieldNames); Try setLength (srcFields, slFieldNames.Count); setLength (dstFields, slFieldNames.Count);
For i := 0 to slFieldNames.Count - 1 do begin srcFields[i] := aSrc.FieldByname(slFieldnames[i]); dstFields[i] := aDst.FieldByname(slFieldnames[i]); End; Finally slFieldNames.Free; End; aSrc.First; while not aSrc.Eof do Begin aDst.Append; For i := 0 do slFieldNames.Count - 1 do dstFields[i].Value := SrcFields[i].Value; aDst.Post; aSrc.Next; End; showmessage('merge '+ aSrc.TableName + ' ok'); End; |
Und nu?
D. Annies - Fr 10.07.09 21:55
(klar kenne ich solche Runtime-Errors, aber ich wusste nicht, wo DER herkommt)
Einen hab ich noch:
zur Laufzeit: EConvertError Format '%p' ungültig oder nicht kompatibel mit Argument.
Ist der auch noch von deinem "Geschnipsel"? :P
Gruß, Deti
D. Annies - Fr 10.07.09 22:03
Ups, ich meine, ich habe es gesehen: dann muss wohl auch 'Punkte' Integer sein, wa?
Nein, gleicher Fehler - aber es sind ja Integer's in den Tabellen, also doch diese Ecke?
alzaimar - Fr 10.07.09 23:24
D. Annies hat folgendes geschrieben : |
Format '%p' ungültig oder nicht kompatibel mit Argument. Ist der auch noch von deinem "Geschnipsel"? |
Siehst Du '%p' in meinem Cöde?
D. Annies - Sa 11.07.09 07:59
Nö, also in meinem Code aber auch nicht. Ich habe jetzt zwei showmessage('hier bin ich') eingebaut, nach den beiden setlength-Anweisungen und nach slFieldNames.free.
Beide Stellen werden noch fehlerfrei erreicht, aber dann kommt die (eine neue) Fehlermeldung: Privilegierte Anweisung
Detlef
D. Annies - Sa 11.07.09 10:01
Habe jetzt weiter eingegrenzt:
For i := 0 to 5 do // slFieldNames.Count - 1 do
wenn ich also slFieldnames.count-1 durch die Zahl 5 ersetze (weil es 6 Felder sind), dann tritt keine Fehlermeldung mehr auf, aber es werden auch keine Daten geschrieben.
Seltsam, seltsam,
Detlef
alzaimar - Sa 11.07.09 10:03
Wie hoch ist den slFieldNames.Count? Wird vielleicht ein leerer Eintrag erzeugt?
Merke: In der Softwareentwicklung ist nichts 'seltsam', sondern immer erklärbar.
D. Annies - Sa 11.07.09 10:15
So, nun klappt es:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| Procedure TForm1.CopyTables (aTblName : String; aSrc, aDst : TTable; aFieldnames : String); Var srcFields, dstFields : Array Of TField; i : Smallint; slFieldNames : TStringList; Begin aSrc.Close; aSrc.TableName := concat(home, '\', aTblName); aSrc.active := true; slFieldNames := CreateStringListFromCommaString(aFieldNames); Try setLength(srcFields, slFieldNames.Count); setLength(dstFields, slFieldNames.Count); For i := 0 to slFieldNames.Count - 1 do begin srcFields[i] := aSrc.FieldByname(slFieldnames[i]); dstFields[i] := aDst.FieldByname(slFieldnames[i]); End; aSrc.First; while not aSrc.Eof do Begin aDst.Append; For i := 0 to slFieldNames.Count - 1 do DstFields[i].Value := SrcFields[i].Value; aDst.Post; aSrc.Next; End; showmessage('merge '+ aSrc.TableName + ' ok'); Finally slFieldNames.Free; End; End; |
Danke für deine Mühe, "alzi"
Gruß aus Lübeck von "Deti"
kkausp - Sa 11.07.09 10:30
Hallo,
Es gibt für die BDE die Delphi Komponente TBATCHMOVE, welche auch das kopieren von Datensätzen ermöglicht.
alzaimar - Sa 11.07.09 14:12
Nur sollte man die BDE in die Tonne treten. Leider, denn daran hatte ich zwischendurch auch mal gedacht.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!