Firebird connector für MySQL, ODBC, duckdb

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

Moderator: thorben.braun

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

Hallo zusammen,

HQBird, https://ib-aid.com/download/docs/hqbird ... on.pdf?v=2 beschreibt in dem verlinkten pdf unter Punkt "3. Plugins for performing external connections with MySQL and ODBC" das Feature, andere Datenbanken direkt aus Firebird heraus über ein Plugin mittels external execute statement lesen und schreiben zu können, zb (Beispiel aus dem verlinkten pdf) so:

Code: Alles auswählen

execute block
returns (
  emp_no bigint,
  birth_date date,
  first_name varchar(14),
  last_name varchar(16),
  gender char(1),
  hire_date date
)
as
  declare dsn_mysql varchar(128);
begin
  dsn_mysql = ':mysql:host=localhost; port=3306; database=employees; user=root';
  for
    execute statement q'{select emp_no, birth_date, first_name, last_name, gender, hire_date
                         from employees
                         order by birth_date desc limit 5}'
    on external dsn_mysql
    as user null password 'sa'
    into emp_no, birth_date, first_name, last_name, gender, hire_date
    do
      suspend;
end
Plugins haben eine ähnliche Basis wie UDRs, sind aber einiges allgemeiner, da u.a. die Struktur der Ergebnismenge nicht feststeht.
Gibt es irgendwo Dokumentation dazu? Plugins sind ein mächtiges Feature, aber wenn nur wenige Eingeweihte wissen, wie man sie schreibt, ist das schon doof ;-) Scheint ja zu gehen mit Firebird, und das auch schon einige Jahre, seit Einführung der Plugin-Schnittstelle mit dem OOAPI bei Firebird 3.

Bevorzugt wäre eine Doku für FPC/Lazarus/Delphi, aber eine für C++ gäbe immerhin Anhaltspunkte, die man mit Wissen über das Schreiben von UDRs evtl übertragen könnte.

Plugins gibt es auch zur Verschlüsselung, die meine ich nicht, sondern explizit Konnektoren zu anderen DBs. Dabei wird man sicher die jeweiligen client-APIs einbinden, denn Firebird tritt dann als Client der ZielDB auf.

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

Wofür braucht man das konkret?
Die Ladeprozesse mit selbstgestrickten Programmen sind doch ungleich einfacher?

Ggf. ziehlst du auf vergleichbare Features in SQL-Server mit Verbindungs-Server.
Diese sind oft eher problematisch als zielführend, denn häufig werden die Ergebnisse eines OpenQuery oder "select * from vbserver...." mittels where oder gar inner Join eingeschränkt.
Hierzu muss man betrachten, dass die Ergebnisse von extern komplett gelesen werden um sie mit Where zu filtern oder auch mit inner join (ist ja auch ein where) einzuschränken.
Da ist es eher zielführend, die Daten erst mit Bulkload o.ä. in die DB zu ziehen und dann abzufragen. Diesen Loadprozess kann man dann zyklisch aktualisieren, denn tatsächlich ändern sich die Daten nicht in kurzer Zeit.

Für die Firebird habe ich schon mal hier einen BulkCopy präsentert, der mit ein paar Optimierungen im .net-FirebirdClient zu erstaunlichen Leistungen kommt. Bis zu 30.000 Update or Insert je Sekunde sind da durchaus drin.
Denn seit FB 3.0 können Statements bis 10MB groß werden, bis zu 255 Tabellen in einem SQL angesprochen werden (auch wenn es jedesmal dieselbe Tabelle ist, zählt sie hier explizit mit). Hinzu können in einem Command-Objekt effektiv bis 2K Parameter definiert werden. Mehr geht zwar auch, dann wird es aber langsamer.
Also definiert man einen SQL mit bis zu 250 Inserts oder 2000 Parametern:
"insert into mytable (f1, f2, ...) values(?, ?, ...);" Das geht natürlich auch mit einem "Update or Insert...".
Ein solcher SQL wird nur 1x analysiert und dann beliebig oft wiederholt, so dass die Ausführungszeit, also der command.Execute(), nur ca. 10ms bei einer lokalen DB benötigt. Somit kommt man auf bis zu 100 Executes / Sekunde, je nach dem, wie schnell die externe Quelle liefern kann. Ein SQL-Server oder eine DB2 schafft das locker.

Also selbst wenn man kurzfristig ein paar 100 Zeilen aus einer anderen DB benötigt, lassen sich diese sehr effizient in die FB laden um sie dann gemeinsam mit anderen Tabellen zu verarzten.
Benutzeravatar
martin.koeditz
Beiträge: 478
Registriert: Sa 31. Mär 2018, 14:35

Naja. Über Plugins kann ich den Funktionsumfang des Systems erweitern. Das können ja ganz vielfältige Dinge wie Authentifizierungsmechanismen oder Exporte im JSON-Format sein.

Wie diese Plugins konkret geschrieben werden, kann ich aber auch nicht sagen. Ich habe eine Anfrage an die FB-Entwickler geschrieben. Mal sehen was da zurück kommt.

Gruß
Martin
Martin Köditz
it & synergy GmbH
Benutzeravatar
martin.koeditz
Beiträge: 478
Registriert: Sa 31. Mär 2018, 14:35

Ich habe eine Antwort von Pavel Cisar erhalten:
Hi,

Einige grundlegende Dokumentationen findest du in `./doc/README.plugins.html` in deiner Firebird-Installation sowie in `./examples/dbcrypt`. Du kannst dir auch den Quellcode für Plugins ansehen, die Teil von Firebird sind, unter `./src/plugins`. Dort findest du den Profiler, Crypt und udr_engine.

Wirf auch auch einen Blick auf die Schnittstellen, die mit Plugins zusammenhängen, in `./include` - `IdlFbInterfaces.h` oder `Firebird.pas`, falls du Pascal verwendest. Ich bin mir nicht sicher, ob das `fbintf1`-Paket (Basis für IBX für Lazarus) von MWA eine bessere Pascal-Unterstützung für Plugin-Entwickler bietet, aber es könnte sich lohnen, es auszuprobieren.

Mit freundlichen Grüßen
Pavel Cisar
IBPhoenix

---
Martin Köditz
it & synergy GmbH
vr2
Beiträge: 246
Registriert: Fr 13. Apr 2018, 00:13

Hi Martin, hi bfuerchau

@Martin: danke für die Weiterleitung an Pavel, das sind einige interessante Infos! examples/dbcrypt geht schon in die Richtung, allerdings geht daraus nicht hervor, wie man einen connector zu einer anderen Engine schreibt, das ist nochmal einiges komplexer. Wegen dem Hinweis von Pavel, dass fbintf das evtl besser unterstützt (da bin ich mir sicher, da es beim Schreiben von UDRs auch so ist) hab ich nun Tony Whyman von MWA angeschrieben mit dem Vorschlag, gemeinsam einen Firebird connector zu einer anderen engine umzusetzen. Bei den UDRs basierend auf fbintf haben wir auch eine Weile zusammengearbeitet und damals meinte Tony, Plugins wären auch nicht großartig anders umzusetzen. Dazu kam es aber nicht mehr.

@bfuerchau: Die Plugin-Schnittstelle bietet so weitreichende Möglichkeiten, die Firebird-Funktionalität zu erweitern, dass es wichtig wäre, wenn die Umsetzung von typischen Anforderungen (mehr als einfachste Beispiele) auch irgendwo brauchbar beschrieben wäre, so dass man überhaupt eine Chance hat, die umzusetzen. Es ist halt wesentlich komplexer, als früher udfs zu schreiben. Falls Du es noch nicht kennst, schau Dir mal https://github.com/duckdb/duckdb an, gerade, weil Du auch im BI-Bereich unterwegs bist. Und dann stell Dir vor, dass Du einen Teil der Möglichkeiten dieser engine auch von Firebird aus nutzen könntest. Also zb csv-, json- oder excel-import, oder AsOf-joins oder grouping sets oder pivoting und allein die Performance bei richtig großen Datenmengen. Oder Export in parquet-files. Firebird hat keinen Schwerpunkt in BI, aber duckdb hat den, u.a. weil es eine spaltenorientierte DB-engine ist. Die Idee ist, sich das von Firebird aus nutzbar zu machen.

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

Unsere BI-Lösung liest die Daten nur aus der FB aus, und das muss möglichst schnell erfolgen, daher auch meine Optimierungsvorschläge und -realisierung.
Die von dir genannten Vorteile berühren mich nicht, da dies alles vom Frontend (in diesem Fall DevExpress Dashbboard mit vielen von mir entwickelten Erweiterungen).
Mittels unserer ETL können beliebige Daten normiert aus fast beliebigen Quellen importiert werden, daher auch der Bulkload.
Fast beliebig daher, dass wir nur via ODBC oder OLEDB-Treiber zugreifen.
Via .Net-ETL können auch native Excel, CSV, REST-API's geladen werden.
Die Verarbeitung der Daten für Präsentation und Analyse erfolgt dann auf dem Web-Server sowie im Web-Client, wo z.B. Pivot's, u.v.m., ja mittlerweile zum Standard gehören.
Die Firebird, gestartet mit 1.5 und aktuell bei 3.0, war für uns die preiswerte Lösung für den Mittelstand, die sich keine teuren SQL-Server oder sogar Cloud (noch teurer) leisten konnten. Zumal wir dazu nur mit wenigen Datentypen auskommen:
Timestamp bzw. Date, Double, Varchar (max. 255), Bigint nur als Identity und das wars.
Alle anderen Funktionen in die DB zu verlegen macht keinen Sinn, da z.B. Drilldown und Filter im Dashboard gar nicht mehr auf die DB zugreifen müssen.
Wenn ich z.B. 1. Mio. Zeilen in einer .Net-Collection im Speicher geladen habe, kann ich diese mit komplexen Ausdrücken in unter 3 Sekunden filtern. Und das mit meinem 2.0GHz-Laptop. Alleine zum Laden von 1. Mio Zeilen mit Where und Index aus der FB dauert bereits 30 Sekunden. Da sich BI-Daten nicht ständig ändern, habe ich einen Cache entworfen, der die Daten hoch komprimiert (alles sind Integer-Verweise) im Speicher vorhält.

Was die spaltenorientierte DB angeht, so hat sich diese im BI-Bereich sogar als nachteilig erwiesen. Ein anderer BI-Anbieter steigt nun um auf relational, da die Ergebnisse da viel effektiver erzielbar sind.
Begründung:
SQL's werden verjoint, mit Where-Klauseln gefiltert und dann per Group By mit mehreren Aggregaten gleichzeitig verarbeitet. Auf Grund der Spaltentechnik ließ sich das eben so nicht mehr performant realisieren. Am Anfang, als die Datenmengen noch klein waren, gings ja noch, aber mit dem ständig steigenden Volumen war die relationale DB dann doch schneller zumal Indexmethoden da gravierend bei helfen.
vr2
Beiträge: 246
Registriert: Fr 13. Apr 2018, 00:13

Nur kurz, relational und spaltenorientiert ist kein Widerspruch. duckdb ist relational.
bfuerchau
Beiträge: 546
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Dann war der Begriff von mir falsch angegeben. Klar, relational hießt ja eben, dass ich Relationen abbilden kann. Ich meine halt zeilenweise.
Allerdings ist beim Abrufen von Daten zeilen- statt spaltenweise, das Datenhandling schon einfacher. Ins besonders dann, wenn man Satzversionen unterstützen will.
Klar ist, bei der spaltenweisen Form ist die Aggregierung sehr schnell. Wenn man die Aggregierung jedoch ausßerhalb der DB macht, ist der Vorteil halt weg.

DevExpress bekommt ein Resultset, und Filterung sowie Aggregierung erfolgt ohne jeden DB-Zugriff. Der Vorteil ist gravierend.
Desweiteren gibts da einen Ausdruckeditor incl. Parser und Berechnung, der mit dem Resultset oder beliebigen anderen Objekten umgehen kann. Dazu dann eine ganze Reihe zusätzlicher Zeilenformeln sowie auch Aggregatformeln.
Und das Beste, es ist total easy, neue Formeln und Aggregate zu integrieren und ist damit vollkommen DB-unabhängig. Diese können dann z.B. in Datengrids genauso zur Anwendung kommen.
Wenn man eine Idee hat, kann man das denn schnell integrieren.
vr2
Beiträge: 246
Registriert: Fr 13. Apr 2018, 00:13

bfuerchau hat geschrieben: Mi 20. Nov 2024, 16:42 Allerdings ist beim Abrufen von Daten zeilen- statt spaltenweise, das Datenhandling schon einfacher. Ins besonders dann, wenn man Satzversionen unterstützen will.
Nein, Du kriegst die Daten natürlich wie sonst bei relationalen DBs tabellarisch, wenn Du ein select a, b, c from tbl machst, das ist nicht wie bei R. Die interne Organisation und Verarbeitung der Daten in der DB ist bei duckDB und anderen solcher DB-Engines/Servern mit spaltenorientierter Architektur / BI-Fokus halt spaltenorientiert. Davon merkst Du außerhalb in diesem Fall nichts außer eben einer anderen Performance. Schau Dir duckdb einfach mal an.
bfuerchau
Beiträge: 546
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Dann stellt sich mir nur die Frage, warum ein mir bekannter anderer BI-Anbieter von der spaltenorientierten DB auf eine zeilenorientierte DB umsteigt, weil diese beim bereitstellen von Zeilendaten einfach schneller ist?
https://de.wikipedia.org/wiki/Spaltenor ... _Datenbank

Was den BI-Fokus angeht, so benötige ich i.d.R. immer alle Spalten einer Tabelle, da die Aggregierung a) per Code durchgeführt wird und b) die Filterung durch Filter-Elemente sowie Drilldown außerhalb der Db stattfindet, da jede DB-Abfrage eben länger dauert als die Durchführung der Aktion InProcess.
Antworten