Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Große Datenmengen richtig verarbeiten bzw. Out of Memory (https://www.delphipraxis.net/197012-grosse-datenmengen-richtig-verarbeiten-bzw-out-memory.html)

Monday 10. Jul 2018 06:27

Datenbank: SQLite • Version: 3 • Zugriff über: ZEOS

Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
Hallo,

ich habe eine große Datenbank ( > 1 Mil. Datensätze ) und möchte die einzelnen Datensätze einzeln weiterverarbeiten.
Bei kleineren Datenmenge habe ich mir nie Gedanken über select & co gemacht. Bei größeren Datenmenge bekomme ich regelmäßig "Out of Memory" Probleme (Nicht zuletzt wegen geringen Arbeitsspeicher (4 GB)). Einzige Möglichkeit sehe ich, die Datensätze nur Häppchenweiße einzulesen. Schön finde ich das allerdings nicht, wie ich finde.

Gibt es noch effektivere Möglichkeiten als diese hier? Hier mein Grundgerüst:

Delphi-Quellcode:

var
temp , stop, a: integer;

begin
// temp ist der "eigene Datensatz Zähler"
//temp := 0; //Anfang der ID's

      Form1.ZQuery3.Close;
      Form1.ZQuery3.SQL.Clear;
      Form1.ZQuery3.SQL.Text := 'select min(id) as mm from tabelle1;';    
      Form1.ZQuery3.Open;
      temp := StrToInt(Form1.ZQuery3.FieldByName('mm').AsString);  



 while stop = 0 do begin //Datensätze nur abschnittsweise laden
   Form1.ZQuery1.Close;
   Form1.ZQuery1.SQL.Clear;
   Form1.ZQuery1.SQL.Text := 'select id,*  from tabelle1 where id >= "'+IntToStr(temp)+'" Limit 100;'; // Limit 100: Ggf. verkleinern
   Form1.ZQuery1.Open;

   Form1.ZQuery3.Close;
   Form1.ZQuery3.SQL.Clear;
   Form1.ZQuery3.SQL.Text := 'select max(id) as mm from tabelle1';
   Form1.ZQuery3.Open;
   if (((StrToInt(Form1.ZQuery3.FieldByName('mm').AsString)-2)) <= temp) then begin stop :=1; exit; end; // Wenn Ende erreicht von DB, dann Schleife beenden


  for a := 0 to ZQuery1.RecordCount-1 do begin
  //  *** Hier die einzelnen Datensätze verarbeiten ***
  end; //for


 end; //while



end;
Liebe Grüße

mkinzler 10. Jul 2018 07:13

AW: Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
In diesem Code liegt viel im Argen.

Warum die Verweise auf eine Instanz eiesn Formulars (Form1). Wo steht dieser Code in Form1 oder in einem anderen Formular?

Was für einen Typ hat das Feld ID? Warum fragst Du es als String ab und wandelst es dann in einen Integer?
Warum fragst Du nicht am Anfang ab, was das Maximum ist sondern bei jedem Schritt?
Welches DBMS?
Warum keine parametrisierte Abfrage?

hoika 10. Jul 2018 08:11

AW: Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
Hallo,

Delphi-Quellcode:
for a := 0 to ZQuery1.RecordCount-1 do begin
  // *** Hier die einzelnen Datensätze verarbeiten ***
  end; //for
select id,*
Brauchst Du wirklich alle Felder der Tabelle?

Das könnte schon das Problem sein.
Hier werden ja nach DB alle Datensätze lokal heruntergeladen und zwischengespeichert.
Ändere das mal ab.

Delphi-Quellcode:
ZQuery1.UniDirectional:= True;
while not ZQuery1.Eof do
begin
  // Datensatz verarbeiten

  ZQuery1.Next;
end;

p80286 10. Jul 2018 08:21

AW: Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
Wenn zu viele Daten von der DB zurück geliefert werden, warum arbeitest Du dann mit
SQL-Code:
'select id,* from tabelle1 where id ...
Zumindest das Feld ID ist dann doppelt.

Wenn Du schon ID zu irgendwelchen Berechnungen und Vergleichen benutzt (-2,<=), dann solltest Du wenigstens eine auf- oder absteigende Reihenfolge sicherstellen
SQL-Code:
order by id asc/desc
Über einen Integer der als Boolean mißbraucht wird, möchte ich mich nicht weiter auslassen.

Und wenn Du min(ID) bzw. max(ID) benötigst, dann kannst Du das zu Anfang Deiner Verarbeitung abfragen, und mußt nicht die ganze Zeit eine Connection offen halten.

Gruß
K-H

Edith:
nach dem Abholen der Datensätze muß der .RecordCount nicht zwangsläufig korrekt sein.

jobo 10. Jul 2018 08:23

AW: Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
Die Frage wäre auch, was die Verarbeitung macht?
z.B.
- Selektierte Daten ändern
- neue erzeugen / ggF. in andere Tabelle
- irgendwas zählen
?

Viele solcher Maßnahmen können durch SQL erledigt werden, ohne dass man überhaupt Daten aus der DB lokal holt.

Ist es nichts von dem oben, sondern -sagen wir mal- ein kleiner Datenabgleich und speichern eines Resultats in einer Datei, könnte man den Datenzugriff schlanker gestalten, Stichwort unidirektionale Cursor, Readonly, etc..
Ich weiß allerdings nicht, was die sqlite clients da können.

himitsu 10. Jul 2018 09:55

AW: Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
Ich hoffe SQLite kann das und ZEROS sollte auch eine Fetch-Funktion bieten,
also wo das DataSet nicht alle Daten runterläd, sondern nur ein Fenster/Teil des ganzen ResultSets.

http://zeoslib.sourceforge.net/viewtopic.php?t=20005
http://forum.lazarus.freepascal.org/...?topic=13192.0

Wenn nicht, dann mußt du das eben selber implementieren, die Abfrage mehrmals mit LIMIT/OFFSET ausführen und die Daten stückchenweise holen.

jaenicke 10. Jul 2018 11:06

AW: Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
Ich habe zu dem Zweck ein Histogramm zur Werteverteilung vom MS SQL Server gezogen und dann immer eine möglichst gleich große Anzahl von Zeilen abgeholt. Auf diese Weise lassen sich Datenmengen sehr effizient abrufen. (In meinem Fall ging es um threadbasierte Verarbeitung von Teilmengen.)

Zitat:

Zitat von p80286 (Beitrag 1406830)
Edith:
nach dem Abholen der Datensätze muß der .RecordCount nicht zwangsläufig korrekt sein.

Nicht nur das, der Abruf bewirkt auch, dass sofort alle Datensätze von der Datenbank abgeholt werden, auch wenn das an der Stelle eigentlich gar nicht nötig wäre. Dadurch dauert der Start der Verarbeitung unnötig lange.

freejay 10. Jul 2018 16:30

AW: Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
Leider kenne ich ZEOS nicht und mit SQLite habe ich auch noch nicht viel gemacht.

Wenn es MySQL wäre und Du die MyDac-Komponenten benutzen würdest, müsste man dort nur FetchAll auf false und UniDirectional auf True setzen, dann wird immer nur die unter FetchRows angegebene Anzahl von Datensätzen im Speicher gehalten und man kann mit einer einzigen While-Schleife beliebig große Datenbanktabellen oder Query-Ergebnisse durchlaufen. Keine Gefahr von Out-Of-Memory.

Vielleicht gibt es ja bei ZEOS & SQLite ähnliche Optionen?

hoika 11. Jul 2018 06:01

AW: Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
Hallo,

Zitat:

FetchAll auf false und UniDirectional auf True
wie ich schon weiter oben geschrieben hatte.
(FetchAll ist standardmäßig ausgeschaltet und sollte nur aus Kompatibilitätsgründen zum Bsp. für den BDE-Ersatz benutzt werden).

mjustin 11. Jul 2018 08:09

AW: Große Datenmengen richtig verarbeiten bzw. Out of Memory
 
Zitat:

Zitat von hoika (Beitrag 1406828)

Delphi-Quellcode:
ZQuery1.UniDirectional:= True;
while not ZQuery1.Eof do
begin
  // Datensatz verarbeiten

  ZQuery1.Next;
end;

Das Setzen von UniDirectional auf True muss vor dem Öffnen (ZQuery1.Open) der Abfrage erfolgen, danach ist es "zu spät", wenn ich mich nicht irre?


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:17 Uhr.
Seite 1 von 3  1 23      

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