2500 Datensätze schnell in eine SQlite3 schreiben

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: 2500 Datensätze schnell in eine SQlite3 schreiben

Beitrag von mse »

DL3AD hat geschrieben:Wozu ist raise und finaly da ?

Das ist im bereits gezeigten Link dokumentiert:
https://www.freepascal.org/docs-html/cu ... 6-24800017
https://www.freepascal.org/docs-html/cu ... 25100017.3
raise wirft die aktuelle exception nochmals um in übergeordneten try..except/finally Blöcken bearbeitet zu werden oder das Programm abzubrechen.
finally wird immer ausgeführt auch wenn im inneren eines try..finally blocks eine exception Auftritt. Hier macht man z.B. notwendige Aufräumarbeiten.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: 2500 Datensätze schnell in eine SQlite3 schreiben

Beitrag von wp_xyz »

try - finally ist dazu da, Resourcen abzusichen, um zu verhindern, dass ein Objekt, das vor try erzeugt worden ist, nicht mehr freigegeben wird, weil es im try-finally Block zu einer Exception gekommen ist. Bei diesem Code

Code: Alles auswählen

var
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
  bmp.LoadFromFile(BITMAP_DATEI);
  Image.Picture.Assign(bmp);
  bmp.Free;
end;

wird das Bitmap nicht mehr freigegeben, wenn z.B. die BITMAP_DATEI nicht gelesen werden kann. Als Folge hat das Programm ein Speicherleck. Mit einem try-finally Block lässt sich das verhindern, weil der Teil in finally immer ausgeführt wird (auch wenn z.b. mit "exit" die Prozedur verlassen wird). Daher ist try-finally extrem wichtig

Code: Alles auswählen

var
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
  try
    if not FileExists(BITMAP_DATEI) then
      exit;
    bmp.LoadfromFile(BITMAP_DATEI);
    Image.Picture.Assign(bmp);
  finally
    bmp.Free// Das wird ausgeführt, wenn die Datei nicht existiert oder das falsche Format hat oder was auch immer
  end;
end;


try-except, dagegen, ist dazu da, das Verhalten bei einer Exception zu ändern. Du willst in deinem Programm gar nicht das Fehler-Fenster sehen, sondern eine Meldung in einem Memo hinterlassen. Das kannst du mit dem weiter oben gezeigten Code erreichen.

Mit raise im except Block kannst du die Exception nochmals auslösen, damit sie im Aufruf-Stack höher gereicht wird und von einem evtl. weiteren try-except/finally Block erneut behandelt wird. Das würde ich in deinem Fall nicht machen.

Dass ich anfangs, von Turbo Pascal kommend, von Exceptions zur Fehler-Detektion (try-except) begeistert war, ist inzwischen verflogen, und ich versuche Exceptions so weit wie möglich zu vermeiden, indem ich die naheliegenden Fehlerursachen abfrage. Wenn darüber hinaus weitere Exceptions auftreten, muss ich mich darum mit try-except nicht kümmern, sie bekommen halt die Standard-Behandlung. (Natürlich muss aber ein try-finally Block vorhanden sein, falls irgendwas wieder auf den Ausgangszustand zurückzustellen ist). Was mich an Exceptions stört, ist dass die IDE bei einer Exception immer anhält, obwohl sie mit try-except behandelt worden ist (das gewünschte Verhalten hat man erst zur Laufzeit außerhalb der IDE). Man kann zwar die IDE anweisen, einen bestimmten Exception-Typ zu ignorieren, aber das trifft dann nicht nur auf diesen einen Fall zu. Glaub mir, es ist ganz schön nervig, wenn du unter den 2500 Records Exceptions auch von nur 100 doppelten Einträgen wegklicken musst.

In deinem fall würde ich vor dem Post suchen, ob der Record mit dem aktuellen Primary Key schon in der Datenbank vorhanden ist, mit entsprechenden Indices geht das ruck-zuck. Nur wenn das nicht der Fall ist, kann geschrieben werden, ansonsten: Memo1.Lines.Add('Record mit Primary Key = ' + ... + ' schon vorhanden.');

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: 2500 Datensätze schnell in eine SQlite3 schreiben

Beitrag von DL3AD »

... Danke für die ausführliche Erklärungen.
Ich habe die Exceptions auch nie benutzt und habe versucht alles mögliche durch logische Überprüfung im Vorfeld abzublocken.
Jaa.. ich glaube der Weg vorher auf Duplikate zu prüfen ist vieleicht besser als die "Notbremse" zu ziehen.
Das überprüfen ob ein Datensatz vorhanden ist bedarf ja im Vorfeld eine DB Abfrage d.h. ich würde ein Select über die Schlüsselfelder Call,Band,Mode und Time machen
und wenn nichts gefunden wird schreiben
Etwa so
1. Datensatz Parsen
2. Select mit den geparsten Daten
3. Prüfen vorhanden Y/N
4. Schreiben in DB wenn nicht vorhanden

Oder denke ich hier zu geradlinig ? :?

Gruß Frank

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: 2500 Datensätze schnell in eine SQlite3 schreiben

Beitrag von mse »

wp_xyz hat geschrieben:Man kann zwar die IDE anweisen, einen bestimmten Exception-Typ zu ignorieren, aber das trifft dann nicht nur auf diesen einen Fall zu. Glaub mir, es ist ganz schön nervig, wenn du unter den 2500 Records Exceptions auch von nur 100 doppelten Einträgen wegklicken musst.

Lazarus kennt bestimmt die Option bei exceptions nicht anzuhalten.
Bei MSEide gibt es dafür die Option 'Project'-'Options'-'Debugger'-'Stop on Excep.' welche man auschalten kann.
DL3AD hat geschrieben:1. Datensatz Parsen
2. Select mit den geparsten Daten
3. Prüfen vorhanden Y/N
4. Schreiben in DB wenn nicht vorhanden

Genau so. Vielleicht
4a. Schreiben in DB wenn nicht vorhanden
4b. Fehlermeldung wenn vorhanden
Exceptions musst du trotzdem abfangen, da ja noch weitere Probleme auftreten könnten. Und wenn man die exceptions schon abfängt, kann man ja auf die vorherige Kontrolle auch verzichten...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: 2500 Datensätze schnell in eine SQlite3 schreiben

Beitrag von wp_xyz »

mse hat geschrieben:Lazarus kennt bestimmt die Option bei exceptions nicht anzuhalten.

Wiegesagt, es gibt unter "Tools" > "Debugger" > "Language exceptions" ein "Add", mit dem man zu igorierende Exception-Typen hinzufügen kann. Aber das gilt projekt-weit. Was, wenn dieselbe Exception an einer anderen Stelle auftritt?

mse hat geschrieben:Exceptions musst du trotzdem abfangen, da ja noch weitere Probleme auftreten könnten.

Eben nicht. Die Exception kommt trotzdem, mit Except kannst du nur das Verhalten beim Auftreten der Exception verändern, nicht aber die Exception selbst verhindern. Der Unterschied ist nur, dass halt dann die Original-Meldung angezeigt wird. Was man machen muss, ist, Resourcen mit einem try-finally-Block zu schützen, aber das ist in dem Code dieses Beitrags nicht nötig: Hier wird kein Objekt erzeugt, keine Ausgabe per BeginUpdate ausgeschaltet, keine Mauscursor verändert usw.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: 2500 Datensätze schnell in eine SQlite3 schreiben

Beitrag von mse »

Schon, aber ein QSL-Report ist eine "Urkunde", da muss man schon genau wissen, was in der DB drin ist und was nicht. Ein sauberer rollback bei einem vermurksten Log ist sicher keine schlechte Idee.
Aber das gilt projekt-weit. Was, wenn dieselbe Exception an einer anderen Stelle auftritt?

Lazarus wird wie MSEide auf exceptions reagieren, indem es auf FPC_RAISEEXCEPTION einen breakpoint setzt. Wenn man diesen breakpoint entfernt, laufen exceptions normal ab.
Zuletzt geändert von mse am Mi 12. Jul 2017, 19:57, insgesamt 1-mal geändert.

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: 2500 Datensätze schnell in eine SQlite3 schreiben

Beitrag von DL3AD »

Hallo wp_xyz,

in meinem Beitrag zuvor hatte ich die vorgehensweise mal umschrieben - das funktioniert nach einem Test auch soweit.
Ob ein Datenmatch vorliegt teste ich mit

Code: Alles auswählen

QueryLog.RecordCount > 0

Gibt es da vieleicht noch eine andere Funktion die besser geeignet ist ?

Gruß
Frank

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: 2500 Datensätze schnell in eine SQlite3 schreiben

Beitrag von wp_xyz »

RecordCount ist - glaube ich - bei ZEOS kein Problem, manchmal liefert es unzuverlässige Werte (aber wahrscheinlich nicht, wenn es nur um die Aussage <> 0 geht), ist manchmal gar nicht implementiert, und hat möglicherweise wieder einen gewissen Overhead. Als Alternative kannst du nach dem Öffnen der Query einfach auf "Query.EOF AND Query.BOF" prüfen. Der Cursor ist nur dann sowohl am Dateiende als auch am Dateianfang, wenn es gar keine Records gibt (http://docwiki.embarcadero.com/Librarie ... ataSet.Eof):

Code: Alles auswählen

function EmptyDataset(ADataset: TDataset): Boolean;
begin
  Result := ADataset.BOF and ADataset.EOF;
end;
...
if EmptyDataset(QueryLog) then     // Datensatz NICHT gefunden
  WriteDB
else
  Memo1.Lines.Add('Datensatz bereits vorhanden')

Antworten