Guten Morgen,
Alexey Kovyazin hat heute ein Video zu Performance-Tests der aktuellen Firebird-Versionen bereitgestellt. Dort sind ein paar Interessante Infos enthalten.
Ihr findet das Video unter:
https://www.youtube.com/watch?v=RLX9JWzthzs
Gruß
Martin
Firebird 5 Performance-Tests
Moderator: martin.koeditz
- martin.koeditz
- Beiträge: 474
- Registriert: Sa 31. Mär 2018, 14:35
Martin Köditz
it & synergy GmbH
it & synergy GmbH
Ehrlich?
Das sind sehr marginale Angaben, da die Software, mit der getestet wird, nicht erwähnt wird. Auf meinem Laptop mir I7 12700H 2,3GHz läuft ein Insert mit meinem Bulkload (für ETL) z.B. mit 4 Felder mit knapp 30.000 Inserts/Sekunde in eine FB 3.0. Dabei kommt die CPU mal gerade auf 1,9GHz Taktrate. Der Test mit FB 4.0 lief unwesentlich schneller.
Mit ca. 20 Feldern komme ich immerhin immer noch auf 12-13000 Inserts/Sekunde.
Die Umgebung ist eine .Net-Anwendung mit dem C#-FB-Client. Da ist natürlich ein wenig Overhead für Konvertierungen und die interen ISC-Verarbeitung (früher FBClient.dll). Ohne Bulkload ist die Rate da eher bei 2000-3000 Inserts/Sekunde.
Würde nur 1 Feld per Insert geschrieben, könnte man da durchaus auf 100.000 Inserts kommen, was noch zu testen wäre.
Der Beispiel-Select ist für normale Systeme eher unrealistisch. Man liest nicht nur 1 Feld mit diversen Joins sondern bei einem Feld prüft man aus welcher Tabelle dies stammt und baut den Select ggf. anders auf, ins besonders eher mit exists als mit inner join.
Es wird auch nichts darüber gesagt, ob die Tabellen passende Indizes haben oder auch nicht.
Desweiteren sind Tabellen in dieser Größe eher gestreut in der DB und nicht sequentiell hintereinander und zusätzlich können Satzversionen vorhanden sein, die überlesen werden müssen.
Das merke ich z.B. dann, wenn die Abfragen nach einem Save-/Restore plötzlich zwischen 10-30% schneller sind, da Tabelle und Indizes beim Restore kompakt neu aufgebaut werden.
Testet man also mit einer kleinen DB, so bis 2GB, kann man fast immer davon ausgehen, dass die Daten da sowieso im Memory liegen. Bei den heutigen Speicherkosten leiste ich mir da durchaus einen Cache von 8GB via firebird.conf.
Das sind sehr marginale Angaben, da die Software, mit der getestet wird, nicht erwähnt wird. Auf meinem Laptop mir I7 12700H 2,3GHz läuft ein Insert mit meinem Bulkload (für ETL) z.B. mit 4 Felder mit knapp 30.000 Inserts/Sekunde in eine FB 3.0. Dabei kommt die CPU mal gerade auf 1,9GHz Taktrate. Der Test mit FB 4.0 lief unwesentlich schneller.
Mit ca. 20 Feldern komme ich immerhin immer noch auf 12-13000 Inserts/Sekunde.
Die Umgebung ist eine .Net-Anwendung mit dem C#-FB-Client. Da ist natürlich ein wenig Overhead für Konvertierungen und die interen ISC-Verarbeitung (früher FBClient.dll). Ohne Bulkload ist die Rate da eher bei 2000-3000 Inserts/Sekunde.
Würde nur 1 Feld per Insert geschrieben, könnte man da durchaus auf 100.000 Inserts kommen, was noch zu testen wäre.
Der Beispiel-Select ist für normale Systeme eher unrealistisch. Man liest nicht nur 1 Feld mit diversen Joins sondern bei einem Feld prüft man aus welcher Tabelle dies stammt und baut den Select ggf. anders auf, ins besonders eher mit exists als mit inner join.
Es wird auch nichts darüber gesagt, ob die Tabellen passende Indizes haben oder auch nicht.
Desweiteren sind Tabellen in dieser Größe eher gestreut in der DB und nicht sequentiell hintereinander und zusätzlich können Satzversionen vorhanden sein, die überlesen werden müssen.
Das merke ich z.B. dann, wenn die Abfragen nach einem Save-/Restore plötzlich zwischen 10-30% schneller sind, da Tabelle und Indizes beim Restore kompakt neu aufgebaut werden.
Testet man also mit einer kleinen DB, so bis 2GB, kann man fast immer davon ausgehen, dass die Daten da sowieso im Memory liegen. Bei den heutigen Speicherkosten leiste ich mir da durchaus einen Cache von 8GB via firebird.conf.
Danke, Martin!
Es gibt neben dem Video auch ein pdf https://ib-aid.com/download/docs/2024/F ... eTests.pdf
und darin der Link zur Testmethodik des ersten Tests (single-thread) https://ib-aid.com/en/simple-insert-upd ... -firebird/
@bfuerchau: Es wird direkt auf der DB getestet, mit execute blocks im Testskript ausgeführt mit isql, so ist der Test ist für alle nachprüfbar.
Bzgl insert-performance kommt es hauptsächlich auf die Satzbreite an, und ob Indizes aktiv sind. Die single-thread-Performance einer CPU spielt demgegenüber eine untergeordnete Rolle.
Im Testskript wird mit 5 aktiven Indizes getestet, schlecht fürs insert, gut fürs update/delete, aber ein typisches Szenario. Hätte man das wirklich so hintereinander, würde man die Indizes vor dem bulk insert deaktivieren. FB5 kann die beim Aktivieren parallel aktualisieren, das ist deutlich schneller als bei den Vorgängern. Das haben sie nicht genutzt, um vergleichbar zu bleiben, nehme ich an.
Die Testergebnisse kann ich soweit bestätigen. Nachdem die ein oder andere Planregression in FB5 beseitigt wurde (deshalb FB 5.0.1 nehmen!), ist FB5 etwas schneller als FB4 und 3.
Es gibt neben dem Video auch ein pdf https://ib-aid.com/download/docs/2024/F ... eTests.pdf
und darin der Link zur Testmethodik des ersten Tests (single-thread) https://ib-aid.com/en/simple-insert-upd ... -firebird/
@bfuerchau: Es wird direkt auf der DB getestet, mit execute blocks im Testskript ausgeführt mit isql, so ist der Test ist für alle nachprüfbar.
Bzgl insert-performance kommt es hauptsächlich auf die Satzbreite an, und ob Indizes aktiv sind. Die single-thread-Performance einer CPU spielt demgegenüber eine untergeordnete Rolle.
Im Testskript wird mit 5 aktiven Indizes getestet, schlecht fürs insert, gut fürs update/delete, aber ein typisches Szenario. Hätte man das wirklich so hintereinander, würde man die Indizes vor dem bulk insert deaktivieren. FB5 kann die beim Aktivieren parallel aktualisieren, das ist deutlich schneller als bei den Vorgängern. Das haben sie nicht genutzt, um vergleichbar zu bleiben, nehme ich an.
Die Testergebnisse kann ich soweit bestätigen. Nachdem die ein oder andere Planregression in FB5 beseitigt wurde (deshalb FB 5.0.1 nehmen!), ist FB5 etwas schneller als FB4 und 3.
Und was nützt mir das, wenn die Performance vom Treiber (C# FirebirdClient) wieder weggefressen wird?
Wenn bei einem Select zur Ermittlung der Schemainformation je Spalte intern ein weiterer Select durchgeführt wird, statt alles auf einmal mit genau einem Select zu laden?
Dies lässt sich am Besten mit den Transaktions-ID's nachvollziehen, die bei einem Select gleich um mehrere ID's hochschnellen, wenn man keine Transaktion startet.
Auch die Performance des Einzelsatz-Selects geht dann sofort in den Keller, da für eine 5-Felder-Abfrage 5 zusätzliche DB-Abfragen erfolgen. Dies ist liniear steigend und gerade bei Mehrbenutzerbetrieb kontraproduktiv.
Für das Laden von Resultsets kann man die "FetchSize" z.B. auf 32.767 setzen, Default 200, so dass auch hier die Anzahl der Requests je Abfrage drastisch senken lässt und die DB entlastet. Man braucht keine Angst zu haben, diesen Wert als Standard zu setzen, da FB-technische Einschränkungen auch weniger Zeilen zurückgeben.
Meine Vorschläge für die nachweisliche Treiberperformance werden aber schlichtweg ignoriert. Ich für meinen Teil, werde für jeden Versionswechsel meine Vorschläge immer wieder in die neuen Quellen einbringen.
Aber wie das schon früher so war. Bei Performanceproblemen nimmt man eher schnellere Hardware als die Software zu optimieren.
Nachtrag:
Und was die Indexanalyse auch zeigt ist, dass die Selectivity eines Indexes auch die aktiven oder noch nicht ausgeräumten Satzversionen mitzählt.
Wenn bei einem Select zur Ermittlung der Schemainformation je Spalte intern ein weiterer Select durchgeführt wird, statt alles auf einmal mit genau einem Select zu laden?
Dies lässt sich am Besten mit den Transaktions-ID's nachvollziehen, die bei einem Select gleich um mehrere ID's hochschnellen, wenn man keine Transaktion startet.
Auch die Performance des Einzelsatz-Selects geht dann sofort in den Keller, da für eine 5-Felder-Abfrage 5 zusätzliche DB-Abfragen erfolgen. Dies ist liniear steigend und gerade bei Mehrbenutzerbetrieb kontraproduktiv.
Für das Laden von Resultsets kann man die "FetchSize" z.B. auf 32.767 setzen, Default 200, so dass auch hier die Anzahl der Requests je Abfrage drastisch senken lässt und die DB entlastet. Man braucht keine Angst zu haben, diesen Wert als Standard zu setzen, da FB-technische Einschränkungen auch weniger Zeilen zurückgeben.
Meine Vorschläge für die nachweisliche Treiberperformance werden aber schlichtweg ignoriert. Ich für meinen Teil, werde für jeden Versionswechsel meine Vorschläge immer wieder in die neuen Quellen einbringen.
Aber wie das schon früher so war. Bei Performanceproblemen nimmt man eher schnellere Hardware als die Software zu optimieren.
Nachtrag:
Und was die Indexanalyse auch zeigt ist, dass die Selectivity eines Indexes auch die aktiven oder noch nicht ausgeräumten Satzversionen mitzählt.
Das ist dann aber ein Problem des Treibers, nutzt Du den hier: https://github.com/FirebirdSQL/NETProvider?bfuerchau hat geschrieben: ↑Do 29. Aug 2024, 09:30 Und was nützt mir das, wenn die Performance vom Treiber (C# FirebirdClient) wieder weggefressen wird?
Wenn bei einem Select zur Ermittlung der Schemainformation je Spalte intern ein weiterer Select durchgeführt wird, statt alles auf einmal mit genau einem Select zu laden?
Mir ist das mit anderen Treibern (fbintf, UIB, php) bisher nicht negativ aufgefallen.
In .Net nehme ich den NetProvider. Andere mögen das auch besser lösen.
Im Git-Projekt kann man das sehr schön im FbDataReader sehen, wie je Feld ein Query durchgeführt wird.
In meinem Merge-Request habe ich das korrigiert. Es wurde jedoch, trotz fehlerfreier Testdurchführung, nicht übernommen.
Aussage (frei übersetzt): "Performanceprobleme wurden noch nicht festgestellt."
Wie auch. Wenn der Treiber das schon immer so macht und mit jeder neuen Hardware (oder des DB-Servers) alles sowieso schneller wird, braucht man ja nichts zu tun .
Die Frage bei den anderen Treibern ist ja auch, ob überhaupt ergänzende Schemainformationen bei einem Resultset geliefert werden.
In C# kann ich ein DataTable-Objekt laden lassen. Dabei werden einige Constraints (Primary Key, Identity, ForeinKey, o.ä.) mit geliefert.
Lese ich mit dem ODBC-Provider aus der PostgreSQL, bekomme ich solche Informationen nicht. Da ich die aber brauche, musste ich mir den passenden SQL dazu erst raussuchen.
Soviel zum Thema Standardisierung. Bei den guten alten ODBC-Treibern (C++, VB6, ADODB-Objekten), ODBC 3.51+, gabs solche Informationen frei Haus, da die ODBC-Vorschriften eingehalten werden mussten. In .Net gibts den Zwang nicht mehr, es reicht von den DBxxx-Klassen zu erben. Selbst der microsofteigene SQL-Server liefert nicht mehr alles wie beim ODBC-Treiber.
Im Git-Projekt kann man das sehr schön im FbDataReader sehen, wie je Feld ein Query durchgeführt wird.
In meinem Merge-Request habe ich das korrigiert. Es wurde jedoch, trotz fehlerfreier Testdurchführung, nicht übernommen.
Aussage (frei übersetzt): "Performanceprobleme wurden noch nicht festgestellt."
Wie auch. Wenn der Treiber das schon immer so macht und mit jeder neuen Hardware (oder des DB-Servers) alles sowieso schneller wird, braucht man ja nichts zu tun .
Die Frage bei den anderen Treibern ist ja auch, ob überhaupt ergänzende Schemainformationen bei einem Resultset geliefert werden.
In C# kann ich ein DataTable-Objekt laden lassen. Dabei werden einige Constraints (Primary Key, Identity, ForeinKey, o.ä.) mit geliefert.
Lese ich mit dem ODBC-Provider aus der PostgreSQL, bekomme ich solche Informationen nicht. Da ich die aber brauche, musste ich mir den passenden SQL dazu erst raussuchen.
Soviel zum Thema Standardisierung. Bei den guten alten ODBC-Treibern (C++, VB6, ADODB-Objekten), ODBC 3.51+, gabs solche Informationen frei Haus, da die ODBC-Vorschriften eingehalten werden mussten. In .Net gibts den Zwang nicht mehr, es reicht von den DBxxx-Klassen zu erben. Selbst der microsofteigene SQL-Server liefert nicht mehr alles wie beim ODBC-Treiber.
Meinst Du den hier : https://github.com/FirebirdSQL/NETProvider/pull/1122 order den https://github.com/FirebirdSQL/NETProvider/pull/1121?In meinem Merge-Request habe ich das korrigiert. Es wurde jedoch, trotz fehlerfreier Testdurchführung, nicht übernommen.
Aussage (frei übersetzt): "Performanceprobleme wurden noch nicht festgestellt."
Ich finde keine entsprechende Aussage. Der erste hat wohl alle Checks bestanden, der zweite zumindest keine Konflikte. Warum die da sitzen und nichts passiert - unklar.
Kommt drauf an, was Du mit "ergänzende Schemainformationen" meinst. Auch ohne prepare, was bei einer Abfrage ohne vorheriges prepare ja implizit gemacht werden muss, kriegst Du Typinfos, nullable usw im sqlda. Das meinst Du vermutlich nicht. Falls Deine Logik aber von umfassenden Schemainfos abhängt wie alle Indizes, auch zusammengesetzte und mehrfache unique Indizes auf einer Tabelle, fragst Du wohl wirklich besser selber die Systemtables ab, einmal. Und wenn der Treiber bei jedem select erstmal die große Runde durchs Dorf macht und für jedes Feld einzeln die Systemtabellen abfragt, ist das eher suboptimal.Die Frage bei den anderen Treibern ist ja auch, ob überhaupt ergänzende Schemainformationen bei einem Resultset geliefert werden.
In solchen Fällen ist ein Testcase sinnvoll, so dass die Maintainer den Performanceverlust durch den Treiber reproduzieren können. Falls der deutlich ist und ggf sogar linear ansteigt, gibt es nicht viel zu diskutieren. Alles andere ist Glaubenssache.
Dafür gibts ja auch eigentlich die Schemaabfragen, die mit ODBC 3.5x festgelegt wurden. Da klappt das auch soweit, da sich die meisten Treiber daran halten.
Mit GetSchema(), also ohne Argument bekommt man die unterstützten Schemata.
Also sollten diese auch bereitgestellt werden.
Bei einem Resultset in C# wird halt z.B. der Primary Key bereitgestellt und das ist eine Indexinformation, die im Resultset meist nicht vorhanden ist. Jedenfalls habe ich noch keine "IsPrimary"-Eigenschaft auf der Spalte gefunden.
Zu den Requests:
Der FbDataReader enthält die Optimierung der Schema-Informationen und kann die Daten generell ca. 10% schneller laden, wenn man GetValues(object[] values) verwendet, was meist die Regel ist.
Der 2. Request verwendet geringere Memory-Allocation von Variablen die nur 1x je Query und nicht 1x je Row benötigt werden. Dies bringt halt bei längeren Resultsets ca. 20% Performance, da der Garbagecollector da eine Menge zu tun bekommt und "Anzahl Zeilen * Anzahl Spalten" Objekte erstellt, die nach Abholen der Daten nicht mehr benötigt werden. Das kostet eben Speicher und Bereitstellungszeit.
Bei 1-zeiligen Queries ist das zwar egal, aber bei mehrzeiligen fällt das schon auf.
Die Antwort zu den Request war i.W: "Wenn das in den meisten Fällen mit kurzen Resultsets doch gut funktioniert, warum soll man das dann für lange Resultsets optimieren?"
Mit GetSchema(), also ohne Argument bekommt man die unterstützten Schemata.
Also sollten diese auch bereitgestellt werden.
Bei einem Resultset in C# wird halt z.B. der Primary Key bereitgestellt und das ist eine Indexinformation, die im Resultset meist nicht vorhanden ist. Jedenfalls habe ich noch keine "IsPrimary"-Eigenschaft auf der Spalte gefunden.
Zu den Requests:
Der FbDataReader enthält die Optimierung der Schema-Informationen und kann die Daten generell ca. 10% schneller laden, wenn man GetValues(object[] values) verwendet, was meist die Regel ist.
Der 2. Request verwendet geringere Memory-Allocation von Variablen die nur 1x je Query und nicht 1x je Row benötigt werden. Dies bringt halt bei längeren Resultsets ca. 20% Performance, da der Garbagecollector da eine Menge zu tun bekommt und "Anzahl Zeilen * Anzahl Spalten" Objekte erstellt, die nach Abholen der Daten nicht mehr benötigt werden. Das kostet eben Speicher und Bereitstellungszeit.
Bei 1-zeiligen Queries ist das zwar egal, aber bei mehrzeiligen fällt das schon auf.
Die Antwort zu den Request war i.W: "Wenn das in den meisten Fällen mit kurzen Resultsets doch gut funktioniert, warum soll man das dann für lange Resultsets optimieren?"
Die Testmethode ist ja gut beschrieben, und man kann sie auch auf der eigenen Hardware ausführen. Ich hab das gemacht, und bin mit dem Ergebnis schon zufrieden. Meine tests wurden mit iSQL und der FB3 Client library durchgeführt, ob der non-legacy Mode noch einmal abweichende Ergebnisse bietet teste ich noch.