Performancevergleich count(*) FB4 vs FB25

Themen rund um den praktischen Einsatz von Firebird. Fragen zu SQL, Performance, Datenbankstrukturen, etc.

Moderator: thorben.braun

Antworten
vr2
Beiträge: 141
Registriert: Fr 13. Apr 2018, 00:13

Hi,

wollte mal eine Umfrage starten, da ich hier auf verschiedenen Systemen ähnliche große Unterschiede beim count(*) zwischen den beiden Serverversionen feststelle (Firebird 3 müsste sich dabei ähnlich verhalten wie 4, nicht getestet). Es geht um count(*) großer Tabellen, also > 1 M Sätze. Dabei habe ich beobachtet, dass die Zeit für die 1. Ausführung bei FB4 deutlich höher ist als bei FB25, Faktor 3 bis Faktor 10, quer über alle möglichen unterschiedliche HW und Windowsversionen. Die getesteten DBs, Tabellen und Serverkonfigurationen stimmen überein. Die 4er DB ist eine restorete Version der 25er. Die getestete Tabelle hat keinen PK. Beide Server nutzen den FilesystemCache von Windows. Zunächst die Frage in die Runde, ob ihr einen ähnlichen Effekt beobachtet habt bzw bestätigen könnt? Wichtig ist, es geht nur um die 1. Ausführung, ab der 2. Ausführung ist FB4 schneller. Es sieht so aus, als bräuchte FB4 länger, den FS-Cache zu laden. Temp-Verzeichnisse/Konfiguration hab ich noch nicht untersucht in dem Zusammenhang.

Superserver, FB 2.5.9, FB 4.0.0, sowohl 32-Bit als auch 64-Bit
DefaultDBCacheSize 4K, PageSize der DBs 16K, ansonsten die firebird.conf bzgl Cache alles auf den Defaultwerten.
DBs liegen auf der selben Platte.

Grüße, Volker
vr2
Beiträge: 141
Registriert: Fr 13. Apr 2018, 00:13

hole den mal hoch - keinem von euch ein Unterschied aufgefallen beim count(*) zwischen FB25 und FB3 oder FB4?

Grüße, Volker
bfuerchau
Beiträge: 349
Registriert: Mo 7. Mai 2018, 18:09

Nein, da ich den i.d.R. nicht brauche.
Aber es gibt eben einige Konfigurationseinstellungen , die Einfluss auf das Verhalten haben. Ggf. sind ein paar Defaults zwischen den Versionen einfach anders.

Z.B.:
Größe der Datenbankseiten, ich nehme immer das Maximum von 16K bei 2.5 und 3.0, ab 4.0 geht wohl auch 32K.
Abschalten des Windowsfilecache. Dadurch muss der FB-Server erst mal viele DB-Seiten in seinen eigenen Cache laden.
Größe der Sortierbereiche und Memory-Blöcke.
Bei einem Count(*) mit Where-Klausel, die Existenz eines passenden Index.

Multithreading:
In 2.5 erhält man die beste Performance mit Windowsfilecache und Classic-Server.
Je Verbindung wird ein neuer Prozess gestartet, der dann alleine für die Verbindung da ist. Dadurch sind parallele Abfragen erst möglich.
Der Superserver ist da nicht geeignet, da nur 1 Thread für eine DB zuständig ist, parallele Abfragen gibt es nicht, diese werden sequentiell abgearbeitet. Somit hat jede Abfrage ihre alleinige Performance.
Nimmt man aber Zeitmessungen vor, so wird die Wartezeit auf dem Server allerdings mitgezählt.
Ab 3.0 gibt es erst echtes Multithreading für 1 DB, so dass jede Connection einen eigenen Thread bekommt.

Und zu guter letzt: Satzversionen!
Dies ist nicht zu verachten, da beim Lesen von Daten die für die aktuelle Transaktion nicht zu verwendenden Versionen, überlesen werden müssen.
Das kostet zusätzliche Zeit.
Deswegen habe ich es mir abgewöhnt, Connectionpooling einzusetzen.
Jede Transaktion beginnt mit Connect und endet mit Close.
Dies stellt sicher, dass ich immer die aktuellsten Daten bekomme und keine offenen Transaktionen einen Sweep verhindern, der das Überlesen von Daten beseitigt.
Um das Entladen des internen Caches nach dem letzten Close zu verhindern, halte ich eine Verbindung permanent offen, auf der ich allerdings nichts tue.

Und noch ein kleiner Tipp:
Ich habe für alle Tabellen eine (selbstverwaltete) Identity-Spalte (seit FB2.0) als BIGINT über die auch ein Unique-Index vorhanden ist.
Um nun die aktuelle Anzahl Zeilen einer Tabelle zu erhalten, kann man aus der RDB$INDIZES die Spalte "rdb$statistics" auslesen. Diese enthält den Kehrwert über die Anzahl Schlüssel der Tabelle. Bei einem UNIQUE-Schlüssel ist also 1/rdb$statistics die aktuelle Anzahl Zeilen der Tabelle.

rdb$statistics dient dem Optimizer um den günstigsten Index für eine Abfrage zu ermitteln.

Und noch ein kleiner Tipp:
Da die meisten Frameworks eine eigene Sortierung ermöglichen (Grids u.ä.) spare ich mir schon länger den "Order By", da dieser in der Gesamtperformance von Nachteil ist. Die Daten müssen erst sortiert werden bevor sie bereitgestellt werden können. Die meisten Programmiersprachen unterstützen aber Sortierungen.

Und noch ein kleiner Tipp:
Index-Strategie!!!
Man soll sich nicht scheuen, durchaus mehrere Indizes zu erstellen.
- Für Join-Beziehungen
- Für Where-Klauseln
Indizes für Group By oder Order BY sind kontraproduktiv sobald man where-Einschränkungen hat. Der Group By funktioniert schneller, wenn man einen Index für die Whereklausel hat.
Nachteil: Bei zuvielen Indizes sinkt die Insert-/Updategeschwindigkeit.
Bei z.B. 30 Indizes (ja die habe ich wirklich) kommen nur noch 15-20 Zeilen/Sekunde in die Tabelle wobei es ohne Index schon mal 20.000 sein können.
Dies ist allerdings nur bei Massendaten (BI+ETL) wichtig.
Benutzeravatar
martin.koeditz
Beiträge: 348
Registriert: Sa 31. Mär 2018, 14:35

Code: Alles auswählen

 In 2.5 erhält man die beste Performance mit Windowsfilecache und Classic-Server.
Ich hatte die beste Performance mit dem Super-Classic erreicht. Dieser macht zwar je Verbindung einen eigenen Prozess auf, nutzt aber den Gesamt-Cache der Firebird-Servers. Habe das aber nie unter Windows getestet.

Gruß
Martin
Martin Köditz
it & synergy GmbH
Gerd
Beiträge: 196
Registriert: Di 1. Okt 2019, 17:13

Hallo in die Runde.

Ich nutze ausschließlich Firebird 4 mit Linux Mint Cinnamon. Insofern geht mein Beitrag an der Umfrage sicherlich vorbei, aber eventuell interessiert das Linux-Anwender(?) oder als 'Tellerrandinformation'.
Die von mir errechnete maximale 'Elapsed time'-Schwankung (4 Messungen) beträgt 0,023 sec (Millisekunde). Für mich ist das akzeptabel.

Datenbank verwendet Seitengröße 8192.
DB-Tabelle hat keinen PK (PRIMARY KEY) und beinhaltet exakt 1.000.000 erzeugte Test-Datensätze.
SQL-Anweisungen wurden von mir jeweils mittels Firebird ISQL Tool abge
setzt.



Viele Grüße
Gerd
Linux Mint 20.3 Una Cinnamon 5.2.7
Firebird 4.0.1, Embedded, ISQL: LI-V4.0.1.2696
Lazarus 2.2.0 - FPC 3.2.2
vr2
Beiträge: 141
Registriert: Fr 13. Apr 2018, 00:13

Hallo,

danke für eure Antworten. Die meisten Verfahren/Tips spielen bei diesem Test keine Rolle, das Problem hat scheinbar einzig mit der zwischem FB25 und FB4 stark unterschiedlichen Ladezeit für den Filesystemcache zu tun.

Testtabelle/Testaufbau ist ganz simpel:

- Windows10 oder 11, Superserver 2.5.9 und 4.0.0, beide 64-Bit oder unterschiedlich, egal
- Die beiden Firebirdserver sind auf dem selben Rechner installiert und haben die gleiche Konfiguration (so weit wie möglich)
- Die beiden Datenbanken liegen auf der selben Platte und haben die gleiche Konfiguration, die 4er ist eine restorete Kopie der 25er
- Pagesize der DBs jeweils 16K

- eine Testtabelle tbl mit 1M Sätzen oder größer, damit man was sieht
- die Testtabelle bleibt während der Tests unverändert, wird nur abgefragt
- Testabfrage: select count(*) from tbl

- Indizes sind hier egal, das count(*) macht in jedem Fall full scan, es gibt keinen where part
- Es sind keine anderen Transaktionen offen, es findet kein garbage collection statt
- es geht nicht um parallele Ausführung
- es geht nur um die erste Ausführungszeit der Testabfrage nach Systemneustart, also um die Ladezeit des Filesystemcache
- genutzt wird der Filesystemcache von Windows

Nach jeder Testabfrage muss man den Rechner neu starten, um den Filesystemcache leerzumachen.

Den Tipp mit dem statistics-Kehrwert kannte ich, aber das kann nicht die Lösung für die beobachtete drastische Performanceverschlechterung zwischen FB25 und FB4 bei einer Standardabfrage wie count(*) from tbl sein. Faktor 3 bis Faktor 10 langsamer konnte ich beobachten.

Das ganze ist nicht akademisch, sondern ein konkretes Kriterium für die Umstellung von FB2.5 auf FB4. Entweder ist an meiner FB4-Konfiguration etwas faul (die sind aber in allen Punkten gleich bei den Servern und DBs, oder es ist ein Firebird-Ticket fällig, der Unterschied ist viel zu groß. Bevor ich da Alarm mache, wollte ich hier nachhören.

In allen anderen Bereichen bin ich sehr zufrieden mit FB4, gute Performance, viele nützliche Features.

Evtl ist es ein Windows-Phänomen. Mag von den Windows-Leuten, die F25 und FB4 auf dem selben Rechner installiert haben, das mal testen?

Grüße, Volker
vr2
Beiträge: 141
Registriert: Fr 13. Apr 2018, 00:13

Ich kann einen reproduzierbaren Testcase liefern, der ohne Rechnerneustart funktioniert. Problemzone ist das Füllen des Windows-Filesystemcache bei FB4. Bei Standardkonfiguration belegt Firebird (2.5 oder 4, egal) 30% des verfügbaren RAM als FS-Cache. Daher hab ich Skripte erstellt, die eine DB in ausreichender Größe erzeugen

- eine große Tabelle "bigone" mit 15 Mio Sätzen und 8 varchar1000-Spalten
- eine kleinere Tabelle "test" mit 1 Mio Sätzen, gleiche Struktur wie bigone

Diese beiden Tabellen werden in einer FB4- und einer FB25-DB mittels execute blocks erzeugt, was 2 DBs von jeweils knapp 3.5 GB Größe ergibt. bigone ist also größer als der FS-Cache, das brauchen wir hier. 30% von 8 GB wären ca 2.4 GB.

Anschließend fragt man die mit isql ab. Dabei sollte jeweils nur der Firebird (4 oder 25) laufen, den man gerade braucht. Für den Test habe ich einen Laptop mit 8 GB RAM und brauchbaren Platten genommen, die RAM-Größe spielt eine Rolle für den Test. Denn bei einer Tabelle, die größer als der von Firebird genutzte Teil des RAMs (= FS-Cache) ist, verdrängt ein Full scan dieser Tabelle alles, was im FS-Cache ist, also genau, was man hier will, denn es geht darum, dessen Ladezeit zu messen, dafür muss er immer wieder neu geladen werden

Entsprechend fragt das Abfrageskript zuerst select count(*) from bigone, dann zweimal select count(*) from test. Das zuerst auf der 4er DB mit dem 4er Server, dann den gestoppt, den 25er Server gestartet und die Abfrage auf der 25er DB mit dem 25er Server.

Bei meinen Tests war es reproduzierbar so, dass Firebird 25 4 mal so schnell von der Platte gelesen und den FS-Cache gefüllt hat wie Firebird 4. Bei den Abfragen war

FB4: Plattendurchsatz Lesen konstant 110 MB / sek, CPU bei 11%, Plattenauslastung 40%
FB25: Plattendurchsatz Lesen konstant 415 MB / sek, CPU bei 20%, Plattenauslastung 85%

So sahen dann auch die Abfragezeiten aus, alle in sek:

FB4:
30 bigone
2.1 test
0.4 test

FB25
7.8 bigone
0.5 test
0.45 test

Und das erklärt natürlich den Performanceunterschied beim select count(*) from tbl.
Jetzt die Frage, warum liest FB4 so viel langsamer von der Platte in den FS-Cache? Beide DBs sind gleich groß und liegen im selben Verzeichnis.

Grüße, Volker

Da man sql-Dateien nicht anhängen kann, als Code:

Code: Alles auswählen

create database 'D:\temp\counttest4.fdb' page_size 16384
user 'sysdba' password 'masterke'
default character set ISO8859_1;

create table bigone (
  F1 VARCHAR (1000),
  F2 VARCHAR (1000),
  F3 VARCHAR (1000),
  F4 VARCHAR (1000),
  F5 VARCHAR (1000),
  F6 VARCHAR (1000),
  F7 VARCHAR (1000),
  F8 VARCHAR (1000)
);

commit;

create table test (
  F1 VARCHAR (1000),
  F2 VARCHAR (1000),
  F3 VARCHAR (1000),
  F4 VARCHAR (1000),
  F5 VARCHAR (1000),
  F6 VARCHAR (1000),
  F7 VARCHAR (1000),
  F8 VARCHAR (1000)
);

commit;

set term #;
execute block
as
declare i int = 0;
declare n int = 15000000;
begin
  while (i < n) do
  begin
    insert into bigone values ('XXXX', 'XXXX', 'XXXX', 'XXXX', 'XXXX', 'XXXX', 'XXXX', 'XXXX');
    i = i + 1;
  end
end#
set term ;#

commit;

set term #;
execute block
as
declare i int = 0;
declare n int = 1000000;
begin
  while (i < n) do
  begin
    insert into test values ('XXXX', 'XXXX', 'XXXX', 'XXXX', 'XXXX', 'XXXX', 'XXXX', 'XXXX');
    i = i + 1;
  end
end#
set term ;#

commit;
Abfrage:

Code: Alles auswählen

connect 'D:\temp\counttest4.fdb' 
user 'sysdba' password 'masterke';

set stats on;

select count(*) dummy from bigone;
commit;

select count(*) anz from test;
commit;

select count(*) anz2 from test;

commit;
Das ganze analog für die 25er DB
vr2
Beiträge: 141
Registriert: Fr 13. Apr 2018, 00:13

Hallo zusammen,
es gibt jetzt ein Firebird-Ticket dazu: https://github.com/FirebirdSQL/firebird/issues/7193

Dort wird das seltsame Performanceverhalten bestätigt und auch die Ursache identifiziert, ein Windows-Flag, das das Lesen von Platte beinflusst und erst seit Firebird 4 benutzt wird.. Bin gespannt

Grüße Volker
Antworten