Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   FireDAC: Viele Records einfügen dauert ziemlich lange (https://www.delphipraxis.net/187568-firedac-viele-records-einfuegen-dauert-ziemlich-lange.html)

Der schöne Günther 10. Dez 2015 09:21

Datenbank: Advantage Local Server • Version: 11 • Zugriff über: FireDAC

FireDAC: Viele Records einfügen dauert ziemlich lange
 
Ich habe eine lokale Datenbank auf meiner SSD. Ich habe eine Tabelle mit drei Spalten:
Integer(FKEY)FloatFloat

Im Speicher habe ich jetzt 50.000 Einträge die ich dort speichern möchte. Meine Herren, das dauert lange. Mit AqTime-Profiler dauert das mit 20 Sekunden ca. vier mal so lange wie "in Echt", aber ich kann wenigstens sehen, was so viel Zeit frisst:

Code:
1x TGünthersDatabase.insertData(): 20 Sek
> 50.000x TFDDataSet.Post: 15 Sek
> >  TFDTable.InternalPost: 10 Sek
> >  TFDTable.InternalLast: 5 Sek
> 1x TFDDataSet.EndBatch: 3 Sek
Mein Code sieht so aus:
Delphi-Quellcode:
var
   einDatum: TDatum;
begin
   meineDatenbank.BeginBatch(False);
   try
      for einDatum in meineDatenAusDemSpeicher do begin
         meineDatenbank.Append();
         meineDatenbank.FieldByName('a').AsInteger := irgendeinFKey;
         meineDatenbank.FieldByName('b').AsFloat := einDatum.Float1;
         meineDatenbank.FieldByName('c').AsFloat := einDatum.Float2;
         meineDatenbank.Post();
      end;
   finally
      meineDatenbank.EndBatch();
   end;
end;
Vor Benutzung von Begin/EndBatch war es noch etwas schlimmer, aber viel hat es auch nicht gebracht.


Was können Profis mir noch für Tipps geben? Das kann doch so nicht richtig sein. Ich lese etwas von "Array DML" (was der Advantage Server aber garantiert nicht unterstützt) und "CachedUpdates". Bin ich hier auf dem richtigen Weg oder wird das auch nichts bringen?

baumina 10. Dez 2015 09:43

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
DisableControls, falls Du Anzeigekomponenten verbunden hast.

jobo 10. Dez 2015 09:45

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Glaube FieldbyName ist nicht so schnelle, lieber Fields[i].
Insgesamt noch lieber Insert Statements mit Parameter statt Dataset, dann jenachdem möglichst selten commiten, am besten nur einmal am Ende.
Falls auf dem FK ein Index liegt, den solange deaktivieren datenbankseitig, sonst hast Du nicht nur 50T inserts, sondern das gleiche nochmal beim Index.

Daniel 10. Dez 2015 09:50

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
ArrayDML war schon ein gutes Stichwort.
Auch kann man mal bei den UpdateOptions schauen. Hat man die Query so eingestellt, dass sie nach jedem .Post() ein .Refresh() macht, dann erklärt dies natürlich die Dauer.

haentschman 10. Dez 2015 09:52

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Moin...:P
Zitat:

Was können Profis mir noch für Tipps geben?
Dataset Edit / Insert / Post verabschieden.... Generische Listen mit den Datenobjekten + direktes SQL = 20000 Datensätze unter 2 Sekunden (nicht genau gemessen...Bauchgefühl :wink: (21..22..fertsch) DBMS: Firebird)

Hinweis: In Firebird kann man Blöcke bilden (1 Block = z.B. 200 SQL) die am Stück ausgeführt werden. Das verschnellert das ganze enorm.

Der schöne Günther 10. Dez 2015 10:13

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

Zitat von jobo (Beitrag 1323922)
Falls auf dem FK ein Index liegt, den solange deaktivieren datenbankseitig, sonst hast Du nicht nur 50T inserts, sondern das gleiche nochmal beim Index.

Ja, tut es. Warum? Keine Ahnung. Ich verstehe nicht mal wirklich was das ist, ich denke mal, das hilft ihm bei SELECT-Statements den Kram schneller zu finden.

Mit der Lese-Dauer bin ich übrigens sehr zufrieden, Löschen dauert deutlich länger, ist aber auch noch akzeptabel. Nur Hinzufügen ist echt schlimm...


Eins verstehe ich nicht: Warum redet Ihr fast alle von einer Query? Es ist eine Tabelle, TFdTable.


Zitat:

Zitat von haentschman (Beitrag 1323924)
[...]

"Alles umschmeißen, anderes DMBS nehmen" wollte ich jetzt am wenigsten hören ;-)


Zitat:

Zitat von baumina (Beitrag 1323921)
DisableControls, falls Du Anzeigekomponenten verbunden hast.

Das übernimmt schon Begin/EndBatch() :-)
Zitat:

Mit der Methode BeginBatch können Sie ressourcenaufwendige Operationen deaktivieren und die Datenmenge so einrichten, dass Aktualisierungen mit maximaler Ausführungsgeschwindigkeit ausgeführt werden. Der Aufruf von BeginBatch deaktiviert:
Die Aktualisierung von datensensitiven Steuerelementen.
Die Aktualisierung von Einschränkungen.
Die Wartung von Aggregaten.
Das Anzeigen von Wartecursors.
Die ähnlich ressourcenaufwendige Verarbeitung in DatS-Objekten, die nicht durch APIs der Datenmenge gesteuert wird.

haentschman 10. Dez 2015 10:16

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

"Alles umschmeißen, anderes DMBS nehmen" wollte ich jetzt am wenigsten hören
Nö...so war das nicht gemeint. Nur der Hinweis auf die Blöcke. Ansonsten ist das ganze ja vergleichbar... :zwinker:

Daniel 10. Dez 2015 10:30

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Die FDTable ist eine Kompatibilitäts-Komponente für diejenigen, die von der BDE kommen. Intern werkelt eine - mehr oder weniger speziell konfigurierte - Query.
Wenn es nur um Insert-Statements geht, kannst Du auch ein FDCommand nutzen, welches eine sehr schlanke Komponente für SQLs ohne Ergebnismenge ist.

jobo 10. Dez 2015 10:32

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1323927)
Zitat:

Zitat von jobo (Beitrag 1323922)
Falls auf dem FK ein Index liegt, den solange deaktivieren datenbankseitig, sonst hast Du nicht nur 50T inserts, sondern das gleiche nochmal beim Index.

Ja, tut es. Warum? Keine Ahnung. Ich verstehe nicht mal wirklich was das ist, ich denke mal, das hilft ihm bei SELECT-Statements den Kram schneller zu finden.

Eins verstehe ich nicht: Warum redet Ihr fast alle von einer Query? Es ist eine Tabelle, TFdTable.

So soll das ja sein ein Index auf Fremdschlüsselfelder, alles gut.
Bei massiven Datenbewegungen (Insert oder Update) auf dem Schlüsselfeld ist der Index leider kontraproduktiv, er ist hauptsächlich eine Hilfe beim schnellen Select.
Der Vorschlag ist aber eher was für den Fall, dass Du mit Delphi Bordmitteln nicht so schnell wirst, wie Du möchtest.

Es reden alle von Query, weil da vermutlich die Erfahrung raus spricht, dass ein Dataset/Table für sowas nicht so geeignet ist.

Mach Dir ein Query Komponente aufs Formular, schreib das Insert Statement rein (parametriert) und fülle die Parameter aus Deinem Memdataset.
Das dann in eine Schleife und Du wirst es wahrscheinlich verstehen, woher die Empfehlung kommt.
Das Queryobjekt oder ein Command schickt einfach die Daten zum Server. Es gibt nahezu kein Overhead im Handling. Das ist beim Dataset eben etwas anders.

Der schöne Günther 10. Dez 2015 10:37

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Der goldene Weg ist es sicher nicht, aber ich habe statt
Delphi-Quellcode:
meinDataset.Append();
[...]
meinDateSet.Post();
nun mal gesagt

Delphi-Quellcode:
meinDataSet.ExecSQL(sqlString, [param1, param2, param3]);

und es ist schon mal 50% schneller. Die Tabellenkomponente benutze ich tatsächlich auch nur zum Einfügen. Hm... :gruebel:

p80286 10. Dez 2015 10:48

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

Zitat von jobo (Beitrag 1323922)
... dann jenachdem möglichst selten commiten, am besten nur einmal am Ende.

das "am besten am Ende" kann auch kontraproduktiv sein.
Ich mache es so, daß alle 1000-2000 Datensätze ein Commit erfolgt. (Oracle, Erfahrungswert)
das ist aber wohl von der Datenbank abhängig.

Gruß
K-H

Daniel 10. Dez 2015 10:48

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Da könntest Du auch das ExecSQL der Connection nutzen. Wenn Dir das langt, sparst Du Dir die zusätzliche Komponente.

Der schöne Günther 10. Dez 2015 10:52

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Habe ich grade versucht, das spart auch etwas, ist aber kein bedeutender Unterschied. Zwei Sekunden für 20.000 Records ist immer noch ziemlich hart. Ich schaue mal ob ich mit dem Index irgendwie etwas machen kann...

haentschman 10. Dez 2015 11:02

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

und es ist schon mal 50% schneller
...das meinte ich mit direktem SQL...:zwinker: Deine Anzahl an Inserts reicht an Masseninserts heran. Wieviele "Durchläufe" deiner 50000 Inserts sind im Laufe eines Jahres zu erwarten? Ggf. mußt du dir auch über die Datenmenge im Gesamten Gedanken machen...

Sir Rufo 10. Dez 2015 11:04

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Der Standardweg sollte immer so ablaufen:
Delphi-Quellcode:
Connection.StartTransaction;
try

  // Viele Datensätze einfügen
  for idx := 1 to 30000 do
  begin
    ...
    Connection.ExecSQL(sqlString, [param1, param2, param3]);
  end;

  Connection.Commit;
except
  Connection.Rollback;
  raise;
end;
Schneller sind dann nur noch BULK INSERTS

Der schöne Günther 10. Dez 2015 11:07

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

Zitat von haentschman (Beitrag 1323937)
Wieviele "Durchläufe" deiner 50000 Inserts sind im Laufe eines Jahres zu erwarten?

Bis zu ein, zwei Dutzend täglich :cyclops:
Aber 50.000 ist ein Extremfall, ich rechne im Schnitt eher mit einem Zehntel der Menge.

Zitat:

Zitat von Sir Rufo (Beitrag 1323938)
Der Standardweg sollte immer so ablaufen:

Tut er :-)
Nur meine Advantage-Datenbank ist die lokale Freeware-Version und hat keine Transaktionen, da sind das nur leere Dummies. Der Monster-Zeitanteil geht wahrscheinlich tatsächlich dafür drauf dass er nach jedem Record schaut ob die referentielle Integrität beim FKEY noch gegeben ist. Würde er das einmal am Schluss machen wäre es bestimmt schneller. Ach ja ... :pale:

jobo 10. Dez 2015 11:49

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1323939)
dass er nach jedem Record schaut ob die referentielle Integrität beim FKEY noch gegeben ist. Würde er das einmal am Schluss machen wäre es bestimmt schneller. Ach ja ... :pale:

Jenachdem wie sehr diese freie DB kastriert ist, kannst Du auch die Constraints deaktivieren.
Da hier das Transaktionhandling abgeklemmt ist, kann ich mir grad spontan nicht vorstellen, wie das dann geht. Stichwort ist jedenfalls: "deferred constraint"
Notfalls kannst Du den Constraint auch droppen und wieder einfügen, genau wie den Index. Das müsste dann natürlich am besten nebenläufig erfolgen.
Oder Du nimmst eine freie DB, die nicht so ein Eunuch ist. ;)

jobo 10. Dez 2015 12:25

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

Zitat von p80286 (Beitrag 1323934)
Zitat:

Zitat von jobo (Beitrag 1323922)
... dann jenachdem möglichst selten commiten, am besten nur einmal am Ende.

das "am besten am Ende" kann auch kontraproduktiv sein.
Ich mache es so, daß alle 1000-2000 Datensätze ein Commit erfolgt. (Oracle, Erfahrungswert)
das ist aber wohl von der Datenbank abhängig.

Ja, kommt auf Rollbackmechanismen und Rollbackplatz an. Wenn man aus 50T commits eine Handvoll macht, sollte das schon spürbar sein.

Bernhard Geyer 10. Dez 2015 14:07

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

Zitat von p80286 (Beitrag 1323934)
Zitat:

Zitat von jobo (Beitrag 1323922)
... dann jenachdem möglichst selten commiten, am besten nur einmal am Ende.

das "am besten am Ende" kann auch kontraproduktiv sein.
Ich mache es so, daß alle 1000-2000 Datensätze ein Commit erfolgt. (Oracle, Erfahrungswert)
das ist aber wohl von der Datenbank abhängig.

Tja. Das liebe Oracle. Hatten mal ein Oracle-Installation soweit in die Knie bekommen (mit einem Import) das sich selbst der Admin nicht mehr anmelden konnte.

Normalerweise sollte man bei einem Import der nur als ganzes gültig ist auch nur am Ende ein Commit machen.
In 2015 sollten selbst "schwachbrüstige" DB-Installationen problemlos Commits nach 100.000 Inserts verkraften.
Diese 1000-2000 Datensätze ist mehr oder minder ein fauler Kompromiss der aufgrund der schlecht Implementierung oder Konfiguration der DB geschuldet ist.
Letztendlich führt man mit so einem Commit die elementare Eigenschaft eines DBMS (ACID) ad absurdum.

p80286 10. Dez 2015 14:15

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1323984)
Diese 1000-2000 Datensätze ist mehr oder minder ein fauler Kompromiss der aufgrund der schlecht Implementierung oder Konfiguration der DB geschuldet ist.

Mach was, wenn Du nur "Kunde" bist. Irgendwann zuckst Du nur noch mit den Schultern und arrangierst Dich mit dem was die Fachleute verbrochen haben.

Gruß
K-H

jobo 10. Dez 2015 14:50

AW: FireDAC: Viele Records einfügen dauert ziemlich lange
 
Zitat:

Zitat von Bernhard Geyer (Beitrag 1323984)
Zitat:

Zitat von p80286 (Beitrag 1323934)
Zitat:

Zitat von jobo (Beitrag 1323922)
... dann jenachdem möglichst selten commiten, am besten nur einmal am Ende.

das "am besten am Ende" kann auch kontraproduktiv sein.
Ich mache es so, daß alle 1000-2000 Datensätze ein Commit erfolgt. (Oracle, Erfahrungswert)
das ist aber wohl von der Datenbank abhängig.

Tja. Das liebe Oracle. Hatten mal ein Oracle-Installation soweit in die Knie bekommen (mit einem Import) das sich selbst der Admin nicht mehr anmelden konnte.

Normalerweise sollte man bei einem Import der nur als ganzes gültig ist auch nur am Ende ein Commit machen.
In 2015 sollten selbst "schwachbrüstige" DB-Installationen problemlos Commits nach 100.000 Inserts verkraften.
Diese 1000-2000 Datensätze ist mehr oder minder ein fauler Kompromiss der aufgrund der schlecht Implementierung oder Konfiguration der DB geschuldet ist.
Letztendlich führt man mit so einem Commit die elementare Eigenschaft eines DBMS (ACID) ad absurdum.

Oh bitte Bernhard, muss das wieder mal raus? Wem nützen denn solche Aussagen?
Wenn man ein paar Millionen Inserts am Stück braucht, muss halt das Rollback entsprechend konfiguriert sein, das hat mit Implementierung nichts zu tun. Und wenn der Admin sich auch nicht anmelden kann, dann muss er halt Anmeldung, Systemkonfiguration und Rollbackverwaltung noch mal üben.
Wer lieber kleine Häppchen mag, muss sich halt selbst darum kümmern, was bei einem Fehler geschieht. Mit "soeinem commit", Du meinst wahrscheinlich diese häufigen Commits bei Masseninsert, raubst Du Dir eine Menge Komfort bei Fehlern. Ad absurdum finde ich etwas übertrieben. Vielleicht ist es wie "immer nur für 10 Euro tanken, weil man nicht weiß, wieviel Geld man dabei hat". Na auch nicht ganz, aber kommt der Sache schon nahe.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:35 Uhr.

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