Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank (https://www.delphipraxis.net/194009-fehler-zu-wenig-arbeitsspeicher-beim-fuellen-der-datenbank.html)

Thomas2017 5. Okt 2017 13:44

Datenbank: Fierbird embedded • Version: 2.1 • Zugriff über: Interbase

Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Hallo,
ich habe mich an einem kleinen Datenbank-Programm versucht und bekomme beim Füllen der Datenbank mit Daten den Fehler "Zu wenig Arbeitsspeicher",
nachdem ca. 180 000 Datensätze geschrieben wurden.

Eckdaten: Delphi 7 prof. (alle verfügbaren und relevanten Updates von Embarcadero installiert)

Bei der Datenbank handelt es sich um eine Firebird-Datenbank (embedded).
Ich nutze die Interbase-Komponenten von Delphi 7.

Hier der Teil, der den Speicherfehler verursacht:
Ich lese aus der Textdatei C:\daten.txt die Daten zeilenweise aus und
übertrage sie folgendermaßen in die Datenbank.

Delphi-Quellcode:
  AssignFile(F, 'C:\daten.txt');
  reset(F);
  repeat
    begin
      readln(F, temp);
      x := x + 1;
      form1.DataSet1.append;
      form1.DataSet1.Edit;
      form1.DataSet1.FieldByName('NAME').AsString := temp;
    end
  until eof(F);

  showmessage('...fertig. ' + inttostr(x) + ' Datensätze');
Lasse ich das Schreiben in die Datenbank weg, tritt der Fehler nicht auf.

Da es ein 32-Bit-Programm ist, beträgt der maximale (virtuelle) Speicher (da noch nicht erweitert, weil keine Ahnung wie...) 2 GB,
der durch das Programm belegt werden kann.
Zur Laufzeit werden jedoch "nur" ~500 MB RAM-Speicher belegt.
Der Rechner hat satt RAM (32 GB) und es ist auch stets genug freier Speicher vorhanden.

Ich habe testweise alle 1000 Datensätze
Delphi-Quellcode:
DataSet1.ApplyUpdates;
abgesetzt, hat aber den Fehler nicht abgestellt.

Ferner habe ich
Delphi-Quellcode:
DataSet1.CachedUpdates :=false;
ausprobiert, was nach meinem Kenntnisstand bewirken soll, das die Änderungen sofort in die Datenbank geschrieben werden sollen und nicht im
virtuellen Speicher zwischengespeichert werden sollen.
Das hat auch nichts gebracht.


Weiss jemand, woran es liegt und was zu tun ist?

mkinzler 5. Okt 2017 13:53

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Das Edit ist nicht notwendig, da Append direkt in den Editmodus wechselt. Ich würde einen expliziten Post einfügen.
Wie sehen die Transaktionseinstellungen aus?

Thomas2017 5. Okt 2017 14:12

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Mit dem Post in der Schleife hat es auch nichts geändert.


Ich habe eine Transaction1 in dem Programm, welche beim Programmstart
aktiv geschaltet wird.
Die anderen Eigenschaften der Transaction1 habe ich bis auf die Datenbank nicht verändert.

Welche Eigenschaften interessieren dich?

Uwe Raabe 5. Okt 2017 14:32

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Zitat:

Zitat von Thomas2017 (Beitrag 1382687)
Ich habe eine Transaction1 in dem Programm, welche beim Programmstart
aktiv geschaltet wird.

Das bedeutet aber, daß die Transaktion über den gesamten Einfügevorgang aktiv ist, oder? Für den Embedded-Driver, der ja im Kontext deines Prozesses läuft, kann das aber schon mal den Speichertod bedeuten.

Versuch doch mal, die Transaktion vor dem Einfügen zu beenden. Geht es dann?

jobo 5. Okt 2017 14:37

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Zitat:

Zitat von Thomas2017 (Beitrag 1382682)
Ich habe testweise alle 1000 Datensätze
Delphi-Quellcode:
DataSet1.ApplyUpdates;
abgesetzt, hat aber den Fehler nicht abgestellt.

Vielleicht lieber die Transaction commiten und eine neue starten?

Thomas2017 5. Okt 2017 15:02

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Ich habe die Tranaction vor dem Einfügen deaktiviert.
Der Fehler bleibt davon aber unberührt.

Wenn die Transaktion nicht active ist, macht es da denn dann in Bezug auf den Fehler überhaupt Sinn,
diese zu committen und dann wieder neu zu starten?


Ich hatte auch getestet, alle 1000 Datensätze das Dataset zu deactivieren und dann wieder vor dem nächsten Datensatz zu activieren,
aber das brachte auch keinen Erfolg.

Kann denn der virtuelle Speicher, der durch das Dataset belegt ist, wieder freigegeben werden ähnlich dem free einer stringlist?

mkinzler 5. Okt 2017 15:06

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
In FireBird geht nichts ohne Transaktionen. Selbt reine Lesezugriffe benötigen einen Transaktionskontext.
Führ mal regelmässig einen Commit durch. (Z.B. je 1000 Datensätze).

hoika 5. Okt 2017 16:28

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Hallo,
ich würde auf Query umstellen.
Wer weiss, wass diese TTable-Dingens im Hintergrund alles anstellt,
um auf einen SQL-Server zugreifen zu können, u.a. werden die Daten ja lokal (in der Exe) gecacht.

jobo 5. Okt 2017 16:33

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
"auf Query umstellen, wer weiß .." würde ich nicht unbedingt, auch wenn es nicht sicher nicht verkehrt wäre. Aber finde ich trotzdem ein gutes Stichwort:

Falls das Dataset noch an die UI gebunden ist, dann rappelt es natürlich ganz schön.

mkinzler 5. Okt 2017 17:06

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Zitat:

um auf einen SQL-Server zugreifen zu können, u.a. werden die Daten ja lokal (in der Exe) gecacht.
Der SQL-Server läuft zudem im Prozessraum der Anwendung.

p80286 5. Okt 2017 21:40

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Da eigentlich alles wichtige schon geschrieben wurde, noch eine Kleinigket, es fehlt das "Closefile".

Gruß
K-H

hoika 5. Okt 2017 21:45

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Hallo,
vielleicht hilft ja auch ein

form1.DataSet1.DisableControls

aber wie schon vorher gesagt -> TQuery benutzen

jobo 5. Okt 2017 22:36

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Zitat:

Zitat von hoika (Beitrag 1382733)
Hallo,
vielleicht hilft ja auch ein

form1.DataSet1.DisableControls

Also das DisableControls wäre das Minimum. Wer will 100T Datensätzen beim Import zusehen?
Und wer will sie nachher sehen? (EnableControls nach Import)

Eine UI Bindung gehört da gar nicht hin. Ist aber ja auch nur Spekulation, dass eine da ist.

TigerLilly 6. Okt 2017 08:36

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Was hat dein Dataset denn für einen Typ?
Wie sieht die Datenbankanbindung aus?

Thomas2017 6. Okt 2017 11:56

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Hallo,
ich habe die Hinweise von euch entsprechend ausprobiert/getestet.

1. alle 1000 Datensätze ein Transaction1.Commit -> Fehler tritt weiterhin auf
2. -> form1.DataSet1.DisableControls -> Fehler tritt auch auf

Nur zur Info:
An dem Dataset hängt nichts mehr dran.
Ich habe das MiniProgramm lediglich zum Befüllen der Datenbank mit Daten aus der besagten Textdatei.

@TigerLilly
Ist ein TIBDataSet, ein TIBDatabase und ein TIBTransaction, wenn Du das meintest mit der Frage.

TigerLilly 6. Okt 2017 12:20

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Ich vermute, dass dein TIBDataSet immer alle Datensätze enthält, die du appended hast, auch wenn du es zwischendurch schließt + wieder öffnest (was steht denn im SelectSQL?).

Setze das SelectSQL mal auf select .... Where 1<>1. Damit lädt das SelectSQL nach dem schließen/öffnen keine Sätze aus der DB + enthält nur die Sätze, die du angefügt hast.

Alternative:
Anstelle des TIBDataSets kannst du dir ja die insert-statements selber bauen und sie via IBSQL direkt in die Datenbank schreiben. Das geht auch flotter.

hoika 7. Okt 2017 09:01

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Hallo,
die Alternative mit der Query wurde bereits gesagt (von mir :))

TigerLilly 7. Okt 2017 09:45

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Zitat:

die Alternative mit der Query wurde bereits gesagt (von mir )
Ja, eh, aber erst wenn ich es sage, stimmt es auch. 8-)

Nein, im Ernst, sorry, ich wollte nur extra nochmal darauf hinweisen + nicht mit deinen Lorbeeren hausieren.

Uwe Raabe 7. Okt 2017 10:04

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Wenn es wirklich daran liegt, daß die Embedded DB zuviel Speicher braucht, könnte man mal versuchen, die Connection zwischendurch zu schließen und wieder neu zu öffnen.

Bernhard Geyer 7. Okt 2017 11:23

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1382781)
Wenn es wirklich daran liegt, daß die Embedded DB zuviel Speicher braucht, könnte man mal versuchen, die Connection zwischendurch zu schließen und wieder neu zu öffnen.

Es muss primär verhindert werden das die gesamte Tabelle in den Speicher geladen wird.
Bei MS Access gabs über ADO die Option Serverseitige Curser zu verwenden damit bei einer TTable-Komponenten nicht der komplette Tabelleninhalt von der Access-Engine nochmal in die Delphi-Teil der Anwendung kopiert wurde. Evtl. gibt das auch bei Interbase.

Ansonsten ist ein TTable-Komponenten nicht zu empfehlen bei Inserts und man sollte Query-KOMponenten mit angepassten INSERT-Statements verwenden. Damit ist man 100%ig sicher das nicht versehentlich die ganze Tabelle in den Speicher geladen wird.

Uwe Raabe 7. Okt 2017 12:40

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1382786)
Bei MS Access gabs über ADO die Option Serverseitige Curser zu verwenden damit bei einer TTable-Komponenten nicht der komplette Tabelleninhalt von der Access-Engine nochmal in die Delphi-Teil der Anwendung kopiert wurde. Evtl. gibt das auch bei Interbase.

Da es sich um den Embedded-Server handelt (eine DLL), spielt sich das Ganze im Adressraum der Anwendung ab. Da ist es vollkommen egal, ob der Server die Datenbank in den Speicher lädt, denn der Server ist in diesem Fall die Anwendung selbst.

nahpets 7. Okt 2017 12:45

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Ja, aber könnte es dann nicht so sein, dass sowohl die DLL, als auch die DataSet-Komponente die gesamten Daten separat im Speicher vorhalten?

Damit hätte doch dann die Anwendung die Daten zweimal im Speicher?

Oder ein anderer Ansatz:

Statt mit 'nem DataSet und Append, 'ne Query nehmen. Das könnte dann sinngemäß ungefähr (ungetestet) so aussehen:
Delphi-Quellcode:
  AssignFile(F, 'C:\daten.txt');
  reset(F);
  form1.Query1.SQL.Clear;
  form1.Query1.SQL.Add('EXECUTE BLOCK BEGIN');
  repeat
    begin
      readln(F, temp);
      x := x + 1;
      form1.Query1.SQL.Add(Format('insert into tabellenname (Name) Values (%s);',[QuotedStr(temp)]));
      // Jeweils 1000 Namen "am Stück" in die Tabelle einfügen.
      // Statt 1000 ggfls. einen angepassten größeren oder kleineren Wert nehmen.
      if x Mod 1000 do begin
        form1.Query1.SQL.Add('END');
        form1.Query1.ExecSQL;
        form1.Query1.SQL.Clear;
        form1.Query1.SQL.Add('EXECUTE BLOCK BEGIN');
      end;
    end
  until eof(F);
  if form1.Query1.SQL.Count > 1 then begin
    form1.Query1.SQL.Add('END');
    form1.Query1.ExecSQL;
    form1.Query1.SQL.Clear;
  end;
  CloseFile(f);

  showmessage('...fertig. ' + inttostr(x) + ' Datensätze');

bnreimer42 7. Okt 2017 13:19

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Schönes Beispiel, aber ein Fehler ist da drinnen:

Delphi-Quellcode:
form1.Query1.SQL.Add(Format('insert into tabellenname (Name) Values (%s);',[QuotedStr(temp)]));
Da kann mit einem falschen String in der Textdatei Blödsinn passieren.

Besser mit Parametern arbeiten:

Delphi-Quellcode:
form1.Query1.SQL.Add('insert into tabellenname (Name) Values (:ParamX);');
form1.Query1.Params[x]:=temp;
x musst Du halt als Zahl hochzählen.

(Auch ungetestet)

Bernhard Geyer 7. Okt 2017 14:10

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1382801)
Da es sich um den Embedded-Server handelt (eine DLL), spielt sich das Ganze im Adressraum der Anwendung ab. Da ist es vollkommen egal, ob der Server die Datenbank in den Speicher lädt, denn der Server ist in diesem Fall die Anwendung selbst.

Nein, ist es nicht. Auf Server-DLL-Seite kann die DB-Engine noch Optimierungen durchführen um nicht wirklich alles Daten im Speicher halten zu müssen. Werden diese Daten dann komplett im Client-Dataset auf Delphi-Seite der Exe gehalten, ist das nicht mehr möglich.

p80286 7. Okt 2017 19:59

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Da ich bisher noch nicht so intensive Bekanntschaft mit embedded Servern hatte, ich meine mich zu erinnern, daß da lokal einige Services laufen, darum bin ich davon ausgegangen, das das Client-Programm zwar auf der selben Maschine aber ansonsten unabhängig von der DB läuft? (z.B. InterbaseServer)

Gruß
K-H

mkinzler 7. Okt 2017 20:09

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Embedded bedeutet, dass die Client-Dll den Serverkern enthält. Keine externen Services usw.

p80286 7. Okt 2017 21:22

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Ok, Danke!

Gruß
K-H

hstreicher 8. Okt 2017 08:57

AW: Fehler "Zu wenig Arbeitsspeicher" beim Füllen der Datenbank
 
Wie ist den die Firebird Datenbank Konfiguriert
- Pagesize
- Buffers DefaultDbCachePages
- werden UDF verwendet
- Forcedwrites
- MaxUnflushedWrites
wo liegt ggf da Temp Verzeichniss und wieviel Platz ist da frei


Pagesize*Buffers ist die Anzahl Bytes die Firebird im Cache vorhält (bei embeded)

Speicherverbrauch bei offenen Transactionen
http://www.firebirdfaq.org/faq118/



mfg Hannes


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:12 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