PHP 7.xx: fbclient.dll bzw. gds32.dll wird nicht installiert.

Forum für Fragen rund um Firebird-Software von Drittanbietern.

Moderator: martin.koeditz

bfuerchau
Beiträge: 70
Registriert: Mo 7. Mai 2018, 18:09

Mo 3. Jun 2019, 12:14

Andere DB's mögen die Anzahl Sätze daher kennen, dass sie die Daten grundsätzlich erst intern in eine Arbeitstabelle kopiert bevor sie zurückgegeben wird.
Dies funktioniert auch i.d.R. nur bei statischen Cursor'n.
Bei dynamischen Cursorn kann sich die Datenbasis während der Abfrage noch ändern.
Manchmal ist der Wert aber auch nur eine Abschätzung der zu erwartenden Daten, je nach Implementation.

Da die Firebird die Daten aber bereits beim Lesen zur Verfügung stellt, ist die Anzahl der Datensätze vorher nicht zu ermitteln.
So etwas zu realisieren würde eine drastische Performanceeinbuße mit sich bringen, da dann tatsächlich erst alles ermittelt werden müsste, bevor die erste Datenzeile zurückgegeben werden kann.
Auf Grund der möglichen sehr komplexen Abfragetechnik, [rekursive] CTE's, union/left/right/inner Joins, derived tables usw., ist dies sehr aufwändig.
Hinzu käme ebenso der z.T. enorme Platzbedarf für die temporäre Kopie der Daten.

Jede Abfrage, die Indizes verwenden kann und somit keine temporären Daten benötigt, ist da immer vorzuziehen.

Wer unbedingt die Anzahl Sätze vorher benötigt, kann auch einen
Select count(*) from
(<Ursprungsselect>) x
durchführen. Er darf sich dann aber nicht über Performancenachteile wundern. Auch Abfragen von unter 100ms verdoppeln sich dadurch in der Queryzeit.

Zu berücksichtigen ist auch noch, dass durch das Versioning, dynamische Cursor ausgeschlossen sind, da Transaktionen nun mal das gleichzeitige Lesen von veränderten Daten durch aktive andere Transaktionen verhindert.
Beim Einsatz von Autocommit, kann also auch eine Count(*) gefolgt von der nächsten Abfrage durchaus ein anderes Ergebnis bringen, es sei denn ich arbeite sowieso alleine mit der Datenbank und verwende keine parallelen Verbindungen.
Benutzeravatar
martin.koeditz
Beiträge: 87
Registriert: Sa 31. Mär 2018, 14:35

Mo 3. Jun 2019, 12:57

@bfuerchau
Danke für die ausführliche Antwort. Damit sind auch einige Interna des DBMS erklärt.
Select count(*) from
(<Ursprungsselect>) x
Vielleicht macht es Sinn dies als Funktion in den PHP-Treiber zu implementieren, mit Hinweis auf all die Nachteile. Dies liegt dann in der Verantwortung des Benutzers.

Gruß
Martin
Martin Köditz
it & synergy GmbH
bfuerchau
Beiträge: 70
Registriert: Mo 7. Mai 2018, 18:09

Mi 5. Jun 2019, 10:20

Ich bezweifle, dass es einen performanten Weg gibt, die Anzahl der möglichen Sätze performant zu ermitteln. Für Fortschrittsanzeigen wäre das sicherlich hilfreich.

Da Firebird grundsätzlich mit Satzversionen arbeitet ist eine schnelle Ermittlung einfach nicht möglich.
Durch das Überlesen von Transaktionsdaten, die für die aktuelle Abfrage nicht relevant sind, ist eben das Scannen der Daten grundsätzlich erforderlich.
Datenbanken ohne Satzversionen benötigen dies nicht.
Der SQL-Server arbeitet nur in Ausnahmefällen mit Satzversionen, nämlich genau dann, wenn ein After-Trigger die geschriebenen Daten nochmals ändert.
Ansonsten gilt z.B. folgendes:
https://community.idera.com/database-to ... ncy-issues

"Read Committed

This is the default Isolation Level for SQL Server and its sole purpose is to prevent “dirty reads”. It does this by placing a SHARED LOCK on the table when it is read. This lock will allow other SELECT transactions to read the same data but will not allow INSERT, UPDATE or DELETE transactions. These subsequent transactions will be BLOCKED until the first SELECT transaction completes."
D.h., dass eine Abfrage von Daten einer Tabelle diese gegen Veränderungen schützt.
Um also nicht zu lange Sperren aufrecht zu halten, ist die DB ja gezwungen, die Daten für den Abruf separat zur Verfügung zu stellen, da ja nicht klar ist, wie lange der Client denn benötig, die Daten zu lesen.

Durch die Satzversionen von Firebird ist dies überhaupt nicht erforderlich, so dass eben alle SQL's in parallelen Abfragen noch möglich sind.

Bei meinen BI-Auswertungen kann es schon mal zu Abfragedauern von mehreren Minuten kommen, da ich schon mit mehr als 30 Joins Abfragen dynamisch erstelle.
Um also die Anzahl der Datensätze zu ermitteln, müsste ich vorher eine Tabelle erstellen (z.B. Global Temporary), mehrere Minuten die Daten per "insert into ... select ... from" kopieren, dann per Count die Anzahl ermitteln und anschließend abrufen.
Nun ist es leider so, dass während des Inserts die Daten auch dem Client bereits verfügbar gemacht werden könnten.

Wenn z.B. bei einem Order By kein Index vorhanden ist, müssen die Daten in einen temporären Bereich gestellt und sortiert werden.
Inzwischen spare ich mir sogar den Order By, da die Ausgabeelemente ja sowieso ihre eigenen Sortierungen durchführen.

Da sind die vielen bereitgestellten Funktionen von Firebird, z.B. die Partition-Funktionen, doch erheblich wichtiger.

Einer meiner Kunden stellt seine Anwendung von SQL-Server auf Firebird um, und muss dabei feststellen, dass die Firebird erheblich performanter als der SQL-Server ist. Dies liegt u.a. auch gerade in der sofortigen Bereitstellung von Ergebnisdaten.

PS:
Ggf. könnte ja auch folgende Eränzung helfen:

select * from (
Select ..., ROW_NUMBER() OVER(ORDER BY <AnyField>) AS RowNbr
from ...
) x
order by RowNbr desc

Dann enthält die Spalte RowNbr die Anzahl der noch zu lesenden Sätze.
Allerdings könnte dies die Abfragedauer auch verlängern, da auf jeden Fall eine komplette Sortierung vor Rückgabe erzwungen wird.
vr2
Beiträge: 44
Registriert: Fr 13. Apr 2018, 00:13

Di 11. Jun 2019, 23:10

Hi Bernd,
Hamburgo hat geschrieben:
So 2. Jun 2019, 15:35
ok, dann muss ich mir da wohl ne Krücke bauen, weil ich diese Info sehr
häufig nutze und da bin ich wohl nicht alleine.
ich nutze php und Firebird schon sehr lange, habe aber einen row_count als Seiteneffekt eines clientseitigen selects noch nie vermisst. Wofür brauchst Du das?

Innerhalb von SPL gibt es Firebirds Kontextvariable row_count, die Dir beim select zumindest sagt, ob es überhaupt eine Ergebnismenge gibt. Das ist manchmal ganz praktisch.

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

Mi 12. Jun 2019, 10:34

Dann lese mal die Doku dazu:
https://firebirdsql.org/refdocs/langref ... count.html

In a FOR SELECT loop, ROW_COUNT is incremented with every iteration (starting at 0 before the first).

After a FETCH from a cursor, ROW_COUNT is 1 if a data row was retrieved and 0 otherwise. Fetching more records from the same cursor does not increment ROW_COUNT beyond 1.

Was hilft dir das nun beim Select?
Da kann man auch selber zählen.
Bei Update/Insert/Delete macht es dann in einer Prozedur schon Sinn, wobei die Clientlibraries häufig auch "AfftectedRows"-Eigenschaften unterstützen.

Eine Satzanzahl ist halt für Fortschrittsanzeigen ganz nett, wenn man den User belustigen will. Das Problem hier:
Je nach Treiber gibt es unterschiedliche Meldungen:
- Nach dem Select und vor dem ersten Fetch (Syntax OK)
- Nach dem 1. Fetch
Wenn ich dann z.B. den .Net-Treiber nehme, dann dauert bei einer komplexen Abfrage die SQL-Analyse mit Zugriffspfaden ca. 6 Sekunden.
Der 1. Fetch, der dann die Ausführung startet pausiert den Treiber für ca. 20-30 Sekunden.
Das anschließende Ergebnis von ca. 40.000 Zeilen kommt dann in ca. 0,8 Sekunden..
Eine Fortschrittsanzeige kann daher überhaupt nicht verwendet werden, da die ja nach 30 Sekunden erst startet und schon gleich wieder voll ist.

Ich denke, dass nicht immer so viele Daten von der DB geladen werden, die Abfragen da aber durchaus auf Grund der Komplexität eben lönger dauern.
Hier wäre eher eine Indexanalyse und entsprechendes Anlegen der Indizes oder u.U. auch ein performateres Redesign des SQL's angebrachter und viel erfolgversprechender.
vr2
Beiträge: 44
Registriert: Fr 13. Apr 2018, 00:13

Mi 12. Jun 2019, 17:40

bfuerchau hat geschrieben:
Mi 12. Jun 2019, 10:34
Dann lese mal die Doku dazu:
https://firebirdsql.org/refdocs/langref ... count.html
[...]
Was hilft dir das nun beim Select?
Du hast doch bestimmt den letzten Satz von meinem Posting gelesen, der das wiedergibt, was in der Doku steht, oder? Und wo ich beschreibe, wofür das brauchbar sein kann, ohne zu zählen. ;-)

Grüße, Volker
Antworten