Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Performance TpFIBDataset (https://www.delphipraxis.net/122867-performance-tpfibdataset.html)

nachti1505 23. Okt 2008 11:45

Datenbank: Firebird • Version: 2.0 • Zugriff über: FIBPlus

Performance TpFIBDataset
 
Ich möchte die Daten eine Tabelle gerne in ein Stringgrid laden. Das StringGrid hat dazu mehrere Spalten (Columns).

Folgender Code:

Delphi-Quellcode:
var
  Dataset: TpFIBDataset;

begin
  Dataset.DisableControls;
  Dataset.First;
  while NOT Dataset.Eof do begin
    for i := 0 to StringGrid.Columns.Count - 1 do begin
      StringGrid.Cells[i, Dataset.RecNo] := Dataset.FindField(StringGrid.Columns[i].DataField);
    end;
    Dataset.Next;
  end;
  Dataset.EnableControls;
end;
Dummerweise benötigt dieses Vorgehen für knapp 1000 Datensätze um die 4sec??? Die Variante mit einem simplen FIBQuery hingegen erledigt das ganze in Bruchteilen davon...

Kommentiert man Zeile 9 (... Dataset.FindField ...) hingegen aus, so beträgt die Laufzeit nur noch Millisekunden. Kann es ein, dass FindField extrem langsam ist? Welche Vorschläge zur Performancesteigerung könnt ihr machen?

Vielen Dank

Hansa 23. Okt 2008 12:44

Re: Performance TpFIBDataset
 
Seit wann gibt es ein stringgrid.Columns ?? Allgemein würde ich immer
SQL-Code:
where
benutzen, anstatt das bereits sichtbare zu durchsuchen.

nachti1505 23. Okt 2008 13:03

Re: Performance TpFIBDataset
 
Zitat:

Zitat von Hansa
Seit wann gibt es ein stringgrid.Columns ??

Ist von mir erweitert worden, um eine DBGrid Funktionalität nachzubilden... hätte ich vllt erwähnen sollen...

Zitat:

Zitat von Hansa
Allgemein würde ich immer
SQL-Code:
where
benutzen, anstatt das bereits sichtbare zu durchsuchen.

Das bereits sichtbare soll nicht durchsucht werden, sondern das Ergebnis einer SQL-Abfrage (ob mit WHERE (gefiltert) oder ohne WHERE (ungefiltert)) im obigen StringGrid dargestellt werden.

Prinzipiell geht meine Frage dahin, ob sich
Delphi-Quellcode:
StringGrid.Cells[i, Dataset.RecNo] := Dataset.FindField(StringGrid.Columns[i].DataField);
performanter ausdrücken lässt, da es von der Laufzeit her wohl an dieser Stelle zu Engpässen kommt.

DeddyH 23. Okt 2008 13:07

Re: Performance TpFIBDataset
 
Ich kenne FIBPlus leider nicht, aber gibt es dort nicht evtl. ein Fields-Array, auf das Du direkt zugreifen könntest?
Delphi-Quellcode:
StringGrid.Cells[i, Dataset.RecNo] := Dataset.Fields[i];
Oder etwas Ähnliches zumindest, da ich mir denken könnte, dass FindField intern mit einer Schleife arbeitet.

nachti1505 23. Okt 2008 13:13

Re: Performance TpFIBDataset
 
Die Idee hatte ich auch schon, ändert leider nicht signifikant etwas. Nutze jetzt aus FIBPlus das FieldByFieldNo. Ändert die Ladezeit von 4s auf 3s... Ist mir aber immer noch zu lang.

Eine (testweise) aufgesetzte UIBQuery benötigt dafür irgendwas im Bereich von 60ms.... Komisch!

Hansa 23. Okt 2008 13:17

Re: Performance TpFIBDataset
 
Zitat:

Zitat von nachti1505
... hätte ich vllt erwähnen sollen...

vllt ? Die Frage an sich wurde durch Unterschlagung wichtiger Informationen so gut wie unbrauchbar gemacht. :zwinker: Die alleine nützt nichts : :glaskugel:

Lasse doch mal hier das Stringgrid weg :
Delphi-Quellcode:
StringGrid.Cells[i, Dataset.RecNo] := Dataset.FindField(StringGrid.Columns[i].DataField);
Es stellt sich schließlich die Frage, ob das zusammengebastelte Stringgrid schuld ist oder ein falsch zusammengebautes Dataset.

DeddyH 23. Okt 2008 13:19

Re: Performance TpFIBDataset
 
Ich hab auch ein wenig das Stringgrid im Verdacht. Evtl. könnte man mit BeginUpdate und EndUpdate noch etwas herausholen, die Frage ist nur, Cols oder Rows.

nachti1505 23. Okt 2008 13:31

Re: Performance TpFIBDataset
 
StringGrid scheint es gar nicht zu sein. Habe aus
Delphi-Quellcode:
StringGrid1.Cells[i, Dataset.RecNo] := Dataset.FieldByFieldNo(i).AsString;
mal folgendes gemacht:
Delphi-Quellcode:
Dataset.FieldByFieldNo(i).AsString;
Und die Laufzeiten bleiben identisch.

Hansa 23. Okt 2008 13:33

Re: Performance TpFIBDataset
 
Wenn das nicht dem Stringgrid zugewiesen wird, wem dann ? :shock: Mache doch einfach ein showmessage oder ein memo.lines.add.

nachti1505 23. Okt 2008 13:40

Re: Performance TpFIBDataset
 
@Hansa...
Durch die eben gezeigte Änderung wird zwar nichts zugewiesen, es ließ sich aber eindeutig klären, ob StringGrid oder Dataset für die Performanzeinbrüche verantwortlich sind. Das das StringGrid nicht mehr in der Anweisung vorkommt und das Dataset nach wie vor das macht, was es machen soll --> Laufzeit hängt vom Dataset ab!

DeddyH 23. Okt 2008 13:42

Re: Performance TpFIBDataset
 
Dann muss ich mich leider ausklinken. Hansa, übernehmen Sie :mrgreen:

nachti1505 23. Okt 2008 13:44

Re: Performance TpFIBDataset
 
@ DeddyH
Schade, trotzdem DANKE

BerndS 23. Okt 2008 14:23

Re: Performance TpFIBDataset
 
Hallo,
ich verwende nie FieldByNumber sondern
Dataset.Fields[index].As...

Warum verwendest du nicht die fibquery, wenn diese so schnell ist???
Das FibDataset nimmt man doch nur, wenn die Datensätze gepuffert werden müssen, um zurück kommen zu können.

Gruß Bernd

nachti1505 24. Okt 2008 08:54

Re: Performance TpFIBDataset
 
So, nochmal eine Zusammenfassung:
Delphi-Quellcode:
var
  Dataset: TpFIBDataset;

begin
  Dataset.First;
  while NOT Dataset.Eof do begin
    for i := 0 to 9 do begin
      Dataset.Fields[i].AsString;
    end;
    Dataset.Next;
  end;
end;
Das ganze ist einfach nur eine Routine, um die Geschwindigkeit des Auslesens von 10 Feldern zu testen, weswegen der resultierende String auch zu nichts zugewiesen wird. Am Dataset hängen keine Sources, Komponenten etc.!

Der Query fragt aus der Datenbank (Adressen) alle Felder der Tabelle ab. In der Tabelle befinden sich ca. 3500 Einträge.

Performance
TpFIBDataset: ~35000 ms
TpFIBQuery: 4600 ms
JvUIBQuery: 600 ms

Also signifikante Unterschiede.

Auf die JvUIB hab ich zum Laden verzichtet, da sich die JvUIBTransaction imho nicht mit der TpFIBTransaction synchronieren lässt.

Workaround für mich um passable Geschwindigkeiten zu erreichen:

1) Begrenzen der Abfrage auf 500 Datensätze
2) Nutzen des pFIBQuery aus dem pFibDataset
Delphi-Quellcode:
Dataset.QSelect.Fields[i].AsString
Vielen Dank an alle Mitdiskutierenden.

BTW: Erstaunlich, dass eine OS-Komponente (JvUIB) schneller ist, als eine kommerzielle (FIBPlus). Trotzdem sind mir die FIBs bequemer :)

exilant 24. Okt 2008 09:24

Re: Performance TpFIBDataset
 
Zitat:

Zitat von nachti1505
So, nochmal eine Zusammenfassung:
Performance
TpFIBDataset: ~35000 ms
TpFIBQuery: 4600 ms
JvUIBQuery: 600 ms

Verstehen tue ich das nicht. Ich fülle hier eine doppelt verkettetet Liste mit > 4.000 Einträgen aus einem tpFibdataset (23 Columns) dem ein Query mit ziemlich heftigen Joins zugrunde liegt.
Die verwendeten Tabellen haben zwischen 12.000 und 15 Mio. rows.
Ausführungszeit des Querys (tpfibdatsat.active := true) mit anschliessendem iterieren durch das Ergebnis incl. Aufbau der Datenstruktur dauert < 1,5 Sec.

Firebird 2.0.1 SuperServer/Linux
Delphi 2007 bzw. Delphi 5 (gleich schnell)


Deine Angabe mit den 35.000ms macht mir daher zu schaffen. 35.000 ms bei 3.500 Datensätzen ergibt lächerliche 10 Records/sec. Da muss was faul sein.

nachti1505 24. Okt 2008 09:28

Re: Performance TpFIBDataset
 
Gib mir doch mal bitte ein Codeschnipsel, wie du durch das Dataset iterierst. Hast du evt. irgendwelche speziellen Optionen im Dataset angeschalten oder abgeschalten? Spielt vielleicht die Transaktion auch noch eine Rolle?

BTW: Was mir aufgefallen ist, wenn die pFIBDatabase lokal läuft (Programm läuft auf dem Server) gibt es einen unheimlichen Geschwindigkeitszuwach gegenüber einer Remotevariante (127.0.0.1:C:\Programme\Firebird_2_1\Datenbank.fdb )...

exilant 24. Okt 2008 10:05

Re: Performance TpFIBDataset
 
Zitat:

Zitat von nachti1505
Gib mir doch mal bitte ein Codeschnipsel, wie du durch das Dataset iterierst. Hast du evt. irgendwelche speziellen Optionen im Dataset angeschalten oder abgeschalten? Spielt vielleicht die Transaktion auch noch eine Rolle?

Delphi-Quellcode:

// dsActiveOrders ist ein tpFibdataset (ein tpFibquery würde es genauso tun,
// hat historische Gründe)

dsActiveOrders.active := true;

while not dsActiveorders.eof do begin
  currentEntry := mylist.addentry;
  currententry.id       := dsActiveOrders.fieldbyname('id').asinteger;
  currententry.StackId  := dsActiveOrders.fieldbyname('stackid').asinteger;
  currententry.StockId  := dsActiveOrders.fieldbyname('stockid').asinteger;
  currententry.Status   := dsActiveOrders.fieldbyname('status').asinteger;
  currententry.Partitial := dsActiveOrders.fieldbyname('partitial').asstring;
  currententry.Orderdate := dsActiveOrders.fieldbyname('orderdate').asdatetime;
  ...
  ...
  dsActiveOrders.next;
end;
currententry.next := NIL;
dsActiveorders.active := false;
Das war's schon. Nichts besonderes. Das Dataset hat eine eigene Transaktion (autostart).

Zitat:

Zitat von nachti1505
BTW: Was mir aufgefallen ist, wenn die pFIBDatabase lokal läuft (Programm läuft auf dem Server) gibt es einen unheimlichen Geschwindigkeitszuwach gegenüber einer Remotevariante (127.0.0.1:C:\Programme\Firebird_2_1\Datenbank.fdb )...

Dazu kann ich nichts sagen. Ich habe hier nur mit entfernten Datenbanken auf Linux Servern zu tun.

Hansa 24. Okt 2008 23:57

Re: Performance TpFIBDataset
 
Liste der Anhänge anzeigen (Anzahl: 1)
Du hast das Stringgrid als Fehlerursache ausgeschlossen. Ich nicht und Test gemacht : Ergebnis : Anhang.

nachti1505 25. Okt 2008 17:01

Re: Performance TpFIBDataset
 
Mhhh, was dein Test und vorallem das Sleep(3000) nun mit einem StringGrid zu tun hat, erschließt sich mir nicht wirklich.

In meinem letzten PerformanceTest habe ich ja nicht mal mehr ein StringGrid benutzt, sondern einfach nur beliebige 10 Dataset.Fields[i].AsString aufgerufen.

Mein letzter Verdacht bezieht sich nun auf meine FIB-Version. Bin immer noch TRIAL-User. Ist es vllt.möglich, dass Devrace die TRIAL von der Performance her beschränkt hat???

Hansa 25. Okt 2008 17:28

Re: Performance TpFIBDataset
 
Zitat:

Zitat von nachti1505
...das Sleep(3000) nun mit einem StringGrid zu tun hat, erschließt sich mir nicht wirklich.

Schwierig, was ? :mrgreen: Das Stringgrid ist völlig aussen vor. Nicht das das bei dir doch noch irgendwo rumschwirrt. Das sleep (3000) zeigt lediglich, wer oder was für die Dauer von 3 Sek. verantwortlich ist. Nämlich nicht etwa über 20000 Datensätze, sondern nur das sleep !!

Zitat:

Zitat von nachti1505
Mein letzter Verdacht bezieht sich nun auf meine FIB-Version. Bin immer noch TRIAL-User. Ist es vllt.möglich, dass Devrace die TRIAL von der Performance her beschränkt hat???

So blöd sind sie nun wirklich nicht. Es ist schon schlimm genug, wie manche Leute die Performance trotz aller Vorsichtsmaßnahmen irgendwie doch so gebremst kriegen, dass sie sogar denken, die Komponenten wären das schuld. 8)

exilant 27. Okt 2008 09:14

Re: Performance TpFIBDataset
 
Zitat:

Zitat von nachti1505
Mein letzter Verdacht bezieht sich nun auf meine FIB-Version. Bin immer noch TRIAL-User. Ist es vllt.möglich, dass Devrace die TRIAL von der Performance her beschränkt hat???

Die Trial entspricht der Vollversion. Du musst den Fehler woanders suchen. Die grundlegenden Mechanismen von FIB, UIB und IBX sind sich sehr ähnlich. Der Grund für Deine extrem unterschiedlichen Mess-Ergebnisse ist nicht in den Komponenten zu suchen. Hast Du vielleicht eine eigene Klasse von TpFibDataset abgeleitet und wenn ja, was tut die? Was macht die Datenbankkiste sonst noch so? Wie hoch ist die CPU Auslastung? Was ist das überhaupt für eine Kiste? Fragen über Fragen...

nachti1505 27. Okt 2008 09:52

Re: Performance TpFIBDataset
 
Nachdem Hansa ja die Ursache auf NICHT-MEHR-VORHANDENE Grids oder Fehler meinerseits schiebt, nochmal ein Versuch zur Problembehebung / -lokalisierung!

1.) Neue VCL-Anwendung
2.) pFIBDatabase, pFIBTransaction, pFIBDataset auf Formular gesetzt und verbunden
3.) in pFIBDataset SQL-Anweisung generiert (SELECT name1, name2, name3, strasse, ort, .... FROM adresse)
4.) Button auf Formular gesetzt und im OnClick:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
    debug: cardinal;
begin
  debug := GetTickCount;
  pFIBDataset1.Active := true;
  while NOT pFIBDataset.EOF do begin
    for i := 1 to 10 do
      pFIBDataset1.Fields[i].AsString;

    pFIBDataset1.Next;
  end;
  pFIBDataset1.Active := false;
  ShowMessage(IntToStr(GetTickCount - Debug));
end;
5.) Ergebnis: bei ca. 3k Datensätze knappe 3500ms

Ergo keine Besserung, trotz ORIGINAL-Kompos (nichts abgeleitet) und selbst OHNE irgendwelche Grids.

Selbiger Testlauf mit JvUIB oder IBX brachte die gewohnten niedrigen Laufzeiten...

Ob ich mich mal an Devrace wende? Oder hat von euch noch einer eine Idee...

BTW: Werde das heute nachmittag noch in einer VirtualMachine probieren *gruebel*

exilant 27. Okt 2008 12:26

Re: Performance TpFIBDataset
 
Zitat:

Zitat von nachti1505
Nachdem Hansa ja die Ursache auf NICHT-MEHR-VORHANDENE Grids oder Fehler meinerseits schiebt, nochmal ein Versuch zur Problembehebung / -lokalisierung!

1.) Neue VCL-Anwendung
2.) pFIBDatabase, pFIBTransaction, pFIBDataset auf Formular gesetzt und verbunden
3.) in pFIBDataset SQL-Anweisung generiert (SELECT name1, name2, name3, strasse, ort, .... FROM adresse)
4.) Button auf Formular gesetzt und im OnClick:
Delphi-Quellcode:
// Delphicode
5.) Ergebnis: bei ca. 3k Datensätze knappe 3500ms

Exakt gleicher obiger Test ergibt bei mir bei 4873 Records eine Laufzeit < 1 Sec.
Bei Dir satte 3,5 Sek. Immerhin ist das Faktor 10 schneller als Deine letzte Angabe (35.000 ms) aber immer noch nicht schnell.
Vermutlich hast Du einfach eine schwächere Maschine. Setze mal das "Unidirektional" Property im TpFibdatset auf "True". Dann
verhält sich das Dataset quasi wie ein tpFibQuery. Bei mir ist die Schleife dann Faktor 3 schneller. Bringt in diesem Fall aber "nur" objektiv was, da die Schleife auch vorher schon sehr schnell durchlaufen wurde und es somit subjektiv keinen Unterschied macht ( bei mir).


Nachtrag:

Der gleiche Test in einer VM (VMWare Workstation 5.5.6) verdeutlicht den erheblichen Unterschied:

Unidirektional False: 3,7 Sek.
Unidirektional True: < 1 Sek.

Ich tippe also mal darauf, das tpFibdataset tatsächlich eher lahm ist. Bei dem was das Teil leistet allerdings auch nicht weiter verwunderlich. Erinnert mich an das "ttable" Syndrom.

Das heisst im Klartext: tpFibDataset nur benutzten, wenn eine "Live"-Datenmenge benötigt wird. Bei mir ist das praktisch nie der Fall. Ich arbeite nicht mit datengebundenen Komponenten. Weiterhin braucht kein Mensch ein lebendes Dataset mit 3500 Records/Rows
Ich würde über das Design der Anwendung nachdenken.

nachti1505 28. Okt 2008 12:41

Re: Performance TpFIBDataset
 
:oops: :wall:

Hmmm.... letzter Testlauf

6k Datensätze - Zeit 400ms..... also weit < 1s

Habe damals für die DB das CharSet UTF8 verwendet. Nachdem nun alles auf WIN1251 zurückgestellt wurde, ist auch die Performance wieder da.....

Vielen, vielen Dank an Deddyh, exilant und auch an Hansa...

Hansa 28. Okt 2008 18:36

Re: Performance TpFIBDataset
 
Zitat:

Zitat von nachti1505
6k Datensätze - Zeit 400ms..... also weit < 1s

trotzdem zu lange, oder sind Blobs oder andere größere Datanstrukturen vorhanden ?

Zitat:

Zitat von nachti1505
Habe damals für die DB das CharSet UTF8 verwendet. Nachdem nun alles auf WIN1251 zurückgestellt wurde, ist auch die Performance wieder da....

Sofern sich das wirklich reproduzieren lässt, dann melde das Devrace. Oder sogar dem Firebird-Projekt. Besser wäre es allerdings, die DB füt Testzwecke hier zur Verfügung zu stellen.

exilant 29. Okt 2008 08:27

Re: Performance TpFIBDataset
 
Zitat:

Zitat von Hansa
Zitat:

Zitat von nachti1505
6k Datensätze - Zeit 400ms..... also weit < 1s

trotzdem zu lange, oder sind Blobs oder andere größere Datanstrukturen vorhanden ?

Wieso lange? Das sind 6.000 Records in weinger als einer halben Sekunde. Wie schnell sollte es denn Deiner Meinung nach sein?


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:02 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-2025 by Thomas Breitkreuz