Marius Popa hat eine interessante Visualisierung der Firebird-Komponenten erstellt. Ein Blick lohnt sich m.E.
Hier der Auszug auf der offiziellen Ankündigun:
FBSimCity
FBSimCity ist eine erkundbare isometrische Stadt, in der jedes Gebäude ein reales Firebird-Subsystem darstellt. Jedes leuchtende Partikel steht für eine Abfrage, die das System durchläuft: vom Client-Hafen über den SQL-Übersetzer bis in die relationale Engine – und anschließend mit den Ergebnissen wieder zurück.
Live-Demo:
https://mariuz.github.io/FBSimCity/
Quellcode:
https://github.com/mariuz/FBSimCity
MIT-Lizenz, reines HTML und JavaScript, kein Build-Schritt erforderlich.
Ziel des FBSimCity-Projekts
Das Projekt richtet sich an Entwicklerinnen und Entwickler, die SQL beherrschen, aber noch nie gesehen haben, was dabei im Hintergrund – also „unter der Haube“ – passiert.
Bitte beachten: FBSimCity ist ein Modell und kein Emulator. Es wird kein SQL tatsächlich analysiert und im Browser wird kein Firebird-Code ausgeführt.
Firebird SimCity
Moderator: martin.koeditz
- martin.koeditz
- Beiträge: 548
- Registriert: Sa 31. Mär 2018, 14:35
Martin Köditz
SynDesk SW GmbH
SynDesk SW GmbH
Ich hab's mir mal angeschaut. Bis auf spezielle Eigenheiten wie Satzversionen kann man sowas eigentlich auf jede beliebige Datenbank anwenden.
Ohne einen Cache funktioniert die DB niemals performant. Ich habe seit Jahren bei den Kundeninstallationen darauf gepocht, den Cache, Sortbereiche usw. einzustellen, was leider nicht so auf fruchtbaren Boden gefallen ist. Der Windows-Filecache, der mitbenutzt wird, wenn man ihn nicht explizit abschaltet, ist nicht immer eine große Hilfe, da der Verdrängungswettbewerb hier um Faktoren größer ist.
Vor ein paar Wochen habe ich dann exemplarisch bei einem Kunden die Werte hochgetrieben.
Bei einem Windowsserver mit 64GB Hauptspeicher habe ich den DefaultDbCachePages auf 32GB (bei 16KB-Seiten = 2.000.000 Seiten) hochgesetzt. Die DB-Größe liegt auch mittlerweile bei ca. 85 GB.
Für die Webanwendung brachte dies dann eine Durchsatzsteigerung zwischen 300 - 500%!
Eine nächtliche Optimierung, die wesentliche Daten schon mal abfragt und in den hauseigenen Cache legt, lief im Schnitt ca. 10 Minuten, was den Start des Web-Servers entsprechend verlängerte.
Nach Erhöhung des DB-Cache benötigte dies nur noch knapp 1 Minute, da es sich i.W. immer um dieselben Basisdaten gehandelt hat, jedoch in unterschiedlichen Aggregatstufen!!
Auch die Erhöhung des TempCacheLimit auf 512M sowie der TempBlockSize auf 8M brachte Vorteile.
Im Umfeld eines BI-Systems, wo erhebliche Datenmengen in unterschiedlichen Ausprägungen abgefragt werden, stellt sich das Gesamtverhalten natürlich anders dar, als in eher bescheideneren ERP-Systemen, die nicht so mit Massenabfragen zu tun haben sondern eher mit einer Vielzahl von Abfragen mit eher kleineren Resultsets.
Da die DB den Cache mit dem letzten Disconnect leert, wird in der Web-Anwendung 1 Verbindung permanent offen gehalten, die aber trotzdem 1 mal pro Minute eine Transaktion startet um keine alten Transaktionen offen zu halten um den Sweeper nicht auszubremsen. Alle anderen Verbindungen werden in einem eigenen Pool verwaltet, der nicht mehr gleichzeitige Verbindungen zur DB erlaubt, als CPU-Threads vorhanden sind, was zu einer besseren Auslastung der DB führt, da weniger Lock-Situationen auftreten. Jede Verbindung wird nach der letzten Aktion noch max. 1 Minute offen gehalten, falls Anfragen noch kommen sollten, danach werden diese auch geschlossen.
Nicht zu verachten ist jedoch eine kleine Einstellung bei Abfragen via Net-Client (andere Clients bieten ggf. vergleichbare Einstellungen).
Hierbei handelt es sich um die FetchSize. Das Maximum ist hier 32767, der Default 200.
Wenn also mehr als 200 Zeilen von der DB abgerufen werden müssen, erfordert dies wieder einen Serverroundtrip um weitere Daten abzuholen.
Daher sollt man bei der FetchSize das Maximum einfach einstellen (Connection-Property oder Command).
Der Server regelt dann selber, wieviele Zeilen tatsächlich per Fetch gesendet werden.
Dies ist von vielen, eher unbekannten, Faktoren abhängig (Blob ja/nein, Anzahl Spalten, Länge der Strings, ...). Aber jeder eingesparte Zugriff zum Server verkürzt die Ladezeiten der Daten.
Bei den Schemaabfragen ist leider ein Eingriff im Treiber selber erforderlich. Der FBDataReader fragt je, nicht kalkulierter, Result-Spalte per zusätzlichem Servercall die Spaltenattribute ab.
Dies sind bei 10 Spalten bis zu 10 zusätzliche DB-Abfragen.
Also 1 Abfrage mit 10 Spalten sind 11 Severcalls, bei 100 Spalten entsprechend dann 101 Calls (wiederum mit eigenem Command und Reader-Objekt).
In meinen Szenarien findet 1 Call in ca. 10 Millisekunden statt. da kann man sich dann ausrechnen, und fragt sich bestimmt, warum die Abfrage einer einzelnen Zeile mit 100 Spalten schon mal fast 1 Sekunde dauert.
Beheben kann man dies am Einfachsten mit berechneten Spalten, denn die Kalkulation auf dem Server ist kürzer als der Overhead der Übertragung.
Zusätzliche Einbußen erfährt man, wenn man auch simple Abfragen nicht in eigene Transaktionen steckt, da alle Abfragen trotzdem mit Transaktionen durchgeführt werden. Dies sind dann zusätzliche Calls, denn hier gibts auch keine Optimierung. Für jedes Command zum Server wird eine Transaktion gestartet, das Command ausgeführt und commited, was auch zusätzliche Serverabfragen bedeutet.
Fazit:
Es gibt viele Stellschrauben, wie man den Durchsatz der Datenbank verbessert. Nicht nur durch Konfiguration sondern ebenso auch durch kleine Anpassungen in der Anwendung.
Ohne einen Cache funktioniert die DB niemals performant. Ich habe seit Jahren bei den Kundeninstallationen darauf gepocht, den Cache, Sortbereiche usw. einzustellen, was leider nicht so auf fruchtbaren Boden gefallen ist. Der Windows-Filecache, der mitbenutzt wird, wenn man ihn nicht explizit abschaltet, ist nicht immer eine große Hilfe, da der Verdrängungswettbewerb hier um Faktoren größer ist.
Vor ein paar Wochen habe ich dann exemplarisch bei einem Kunden die Werte hochgetrieben.
Bei einem Windowsserver mit 64GB Hauptspeicher habe ich den DefaultDbCachePages auf 32GB (bei 16KB-Seiten = 2.000.000 Seiten) hochgesetzt. Die DB-Größe liegt auch mittlerweile bei ca. 85 GB.
Für die Webanwendung brachte dies dann eine Durchsatzsteigerung zwischen 300 - 500%!
Eine nächtliche Optimierung, die wesentliche Daten schon mal abfragt und in den hauseigenen Cache legt, lief im Schnitt ca. 10 Minuten, was den Start des Web-Servers entsprechend verlängerte.
Nach Erhöhung des DB-Cache benötigte dies nur noch knapp 1 Minute, da es sich i.W. immer um dieselben Basisdaten gehandelt hat, jedoch in unterschiedlichen Aggregatstufen!!
Auch die Erhöhung des TempCacheLimit auf 512M sowie der TempBlockSize auf 8M brachte Vorteile.
Im Umfeld eines BI-Systems, wo erhebliche Datenmengen in unterschiedlichen Ausprägungen abgefragt werden, stellt sich das Gesamtverhalten natürlich anders dar, als in eher bescheideneren ERP-Systemen, die nicht so mit Massenabfragen zu tun haben sondern eher mit einer Vielzahl von Abfragen mit eher kleineren Resultsets.
Da die DB den Cache mit dem letzten Disconnect leert, wird in der Web-Anwendung 1 Verbindung permanent offen gehalten, die aber trotzdem 1 mal pro Minute eine Transaktion startet um keine alten Transaktionen offen zu halten um den Sweeper nicht auszubremsen. Alle anderen Verbindungen werden in einem eigenen Pool verwaltet, der nicht mehr gleichzeitige Verbindungen zur DB erlaubt, als CPU-Threads vorhanden sind, was zu einer besseren Auslastung der DB führt, da weniger Lock-Situationen auftreten. Jede Verbindung wird nach der letzten Aktion noch max. 1 Minute offen gehalten, falls Anfragen noch kommen sollten, danach werden diese auch geschlossen.
Nicht zu verachten ist jedoch eine kleine Einstellung bei Abfragen via Net-Client (andere Clients bieten ggf. vergleichbare Einstellungen).
Hierbei handelt es sich um die FetchSize. Das Maximum ist hier 32767, der Default 200.
Wenn also mehr als 200 Zeilen von der DB abgerufen werden müssen, erfordert dies wieder einen Serverroundtrip um weitere Daten abzuholen.
Daher sollt man bei der FetchSize das Maximum einfach einstellen (Connection-Property oder Command).
Der Server regelt dann selber, wieviele Zeilen tatsächlich per Fetch gesendet werden.
Dies ist von vielen, eher unbekannten, Faktoren abhängig (Blob ja/nein, Anzahl Spalten, Länge der Strings, ...). Aber jeder eingesparte Zugriff zum Server verkürzt die Ladezeiten der Daten.
Bei den Schemaabfragen ist leider ein Eingriff im Treiber selber erforderlich. Der FBDataReader fragt je, nicht kalkulierter, Result-Spalte per zusätzlichem Servercall die Spaltenattribute ab.
Dies sind bei 10 Spalten bis zu 10 zusätzliche DB-Abfragen.
Also 1 Abfrage mit 10 Spalten sind 11 Severcalls, bei 100 Spalten entsprechend dann 101 Calls (wiederum mit eigenem Command und Reader-Objekt).
In meinen Szenarien findet 1 Call in ca. 10 Millisekunden statt. da kann man sich dann ausrechnen, und fragt sich bestimmt, warum die Abfrage einer einzelnen Zeile mit 100 Spalten schon mal fast 1 Sekunde dauert.
Beheben kann man dies am Einfachsten mit berechneten Spalten, denn die Kalkulation auf dem Server ist kürzer als der Overhead der Übertragung.
Zusätzliche Einbußen erfährt man, wenn man auch simple Abfragen nicht in eigene Transaktionen steckt, da alle Abfragen trotzdem mit Transaktionen durchgeführt werden. Dies sind dann zusätzliche Calls, denn hier gibts auch keine Optimierung. Für jedes Command zum Server wird eine Transaktion gestartet, das Command ausgeführt und commited, was auch zusätzliche Serverabfragen bedeutet.
Fazit:
Es gibt viele Stellschrauben, wie man den Durchsatz der Datenbank verbessert. Nicht nur durch Konfiguration sondern ebenso auch durch kleine Anpassungen in der Anwendung.
- martin.koeditz
- Beiträge: 548
- Registriert: Sa 31. Mär 2018, 14:35
Danke für deine Ergänzungen. Hier kann man einiges rausziehen.
Ich finde die umgesetzte Visualisierung interessant. Hier kann man schön sehen, wie viele verschiedene Komponenten in so einem System miteinander arbeiten. Es ist nun mal nicht nur die Datenbank.
Ich finde die umgesetzte Visualisierung interessant. Hier kann man schön sehen, wie viele verschiedene Komponenten in so einem System miteinander arbeiten. Es ist nun mal nicht nur die Datenbank.
Martin Köditz
SynDesk SW GmbH
SynDesk SW GmbH
Um es mit Spocks Worten zu sagen: Das ist korrekt.
Aber dazu hatte ich auf Grund anderer Datenbanken bereits Vorstellungen, wie die DB funktioniert
.
Aber dazu hatte ich auf Grund anderer Datenbanken bereits Vorstellungen, wie die DB funktioniert