Von UDF zu UDR in Firebird 5

Soundex, Kölner Phonetik, PSQL, Free Pascal und Visual C++ im Praxistest

IBExpert Ltd - Technical White Paper

Executive Summary

Firebird-Anwendungen können die Datenbank-Engine seit vielen Jahren um externe Funktionen erweitern. In älteren Installationen geschah dies häufig mit UDFs (User Defined Functions). Moderne Firebird-Versionen stellen dafür mit UDRs (User Defined Routines) eine deutlich besser integrierte Architektur bereit.

Dieses White Paper beschreibt den Weg von UDF zu UDR anhand eines praktischen Beispiels: phonetische Namensvergleiche mit Soundex, einer deutsch angepassten Soundex-Variante, Kölner Phonetik sowie Distanz- und Ähnlichkeitsfunktionen. Dieselben Funktionen wurden als Firebird-PSQL-Stored-Functions, als native UDR mit Lazarus/Free Pascal und als native UDR mit Microsoft Visual C++ 2022 implementiert.

Der überraschendste Befund: Nicht die Programmiersprache war der wichtigste Performancefaktor. Nachdem Free Pascal und C++ weitgehend denselben Low-Level-Algorithmus verwendeten, lag die optimierte FPC-Version typischerweise nur noch etwa 10 bis 25 Prozent hinter Visual C++.

1. Von UDF zu UDR

UDFs waren über viele Firebird-Generationen ein bewährter Weg, Berechnungen in externe DLLs bzw. Shared Libraries auszulagern. Die alte UDF-Schnittstelle stammt jedoch aus einer früheren Generation des API-Designs.

UDRs sind der moderne Nachfolger. SQL ruft weiterhin nativen Code auf, die Integration erfolgt jedoch über Firebirds moderne Plugin- und Objekt-API. Datentypen, NULL-Behandlung, Metadaten, Zeichensätze und Lebenszyklus sind sauberer eingebunden. Für neue Erweiterungen unter Firebird 5 sollte eine UDR daher als natürlicher Ersatz für klassische UDFs betrachtet werden.

2. Alternative: Stored Functions in PSQL

Viele Algorithmen lassen sich vollständig als Firebird Stored Function in PSQL implementieren. Das vereinfacht die Verteilung erheblich: keine zusätzliche DLL, keine Linux-Shared-Library und keine plattformspezifische Binärdatei.

PSQL ist besonders interessant, wenn einfache Installation, Backup/Restore und Plattformunabhängigkeit wichtiger sind als maximale Rechenleistung. Entscheidend ist nicht, ob PSQL eine Aufgabe lösen kann, sondern ob seine Geschwindigkeit für das konkrete Aufrufvolumen ausreicht.

3. Warum phonetische Namenssuche?

Exakte Stringvergleiche sind bei Namen oft unzureichend. Klemt, Klemmt, Klempt und Klemp sind technisch vier unterschiedliche Zeichenketten, können aber bei einer Personensuche zusammengehören.

Phonetische Algorithmen bilden Namen auf Codes ab, die sich stärker an der Aussprache als an der exakten Schreibweise orientieren. Dadurch lassen sich Tippfehler, historische Schreibweisen und Varianten besser erkennen.

4. Soundex

Soundex erzeugt typischerweise einen kurzen Code aus einem Anfangsbuchstaben und Ziffern für ähnlich klingende Konsonantengruppen. Das Verfahren ist einfach und schnell, wurde jedoch primär für englische Namen entwickelt.

Im Projekt wurden deshalb SOUNDEX und SOUNDEX_DE umgesetzt. Die deutsche Variante normalisiert unter anderem Ä/AE, Ö/OE, Ü/UE, ß/SS sowie typische Buchstabenkombinationen.

5. Kölner Phonetik

Für deutsche Namen ist die Kölner Phonetik häufig geeigneter. Sie arbeitet mit kontextabhängigen Regeln und erzeugt eine Ziffernfolge variabler Länge.

Klemt → 4562, Klemmt → 4562, Klempt → 45612, Klemp → 4561. Klemt und Klemmt werden damit direkt phonetisch identisch; die anderen Varianten liegen nur geringfügig entfernt.

6. Distanz und Similarity

COLOGNE_DISTANCE berechnet zunächst für beide Namen die Kölner Phonetik und anschließend die Levenshtein-Distanz der Codes. 0 bedeutet identisch; 1 bedeutet eine notwendige Einfügung, Löschung oder Ersetzung.

PHONETIC_SIMILARITY übersetzt dies in einen Wert von 0 bis 100. In unserem Beispiel ergeben Klemt/Klemmt 100, Klemt/Klempt 80 und Klemt/Klemp 75.

7. Drei Implementierungen, gleiche Ergebnisse

Die fünf Funktionen SOUNDEX, SOUNDEX_DE, COLOGNE_PHONETIC, COLOGNE_DISTANCE und PHONETIC_SIMILARITY wurden als PSQL, als Lazarus/FPC-UDR und als Visual-C++-UDR umgesetzt.

Vor dem Performancevergleich wurden 10.000 Testdatensätze geprüft. In der finalen Version gab es bei allen fünf Funktionen 0 Abweichungen. Identische Checksums stellten zusätzlich sicher, dass alle Implementierungen dieselben Ergebnisse verarbeiteten.

8. PSQL versus native UDR

PSQL erwies sich bei den einfachen phonetischen Funktionen als überraschend brauchbar. Mit zunehmender Rechenarbeit wächst der Vorteil nativer UDRs deutlich, besonders bei Distanz- und Similarity-Berechnungen.

Funktion

Native UDR (typisch)

PSQL (typisch)

Einordnung

SOUNDEX

~0,04 s

~0,8 s

Native deutlich schneller

SOUNDEX_DE

~0,05 s

~0,9 s

Native deutlich schneller

COLOGNE_PHONETIC

~0,04 s

~1,6 s

Native deutlich schneller

COLOGNE_DISTANCE

~0,06 s

~4,5 s

Native sehr deutlich schneller

PHONETIC_SIMILARITY

~0,06 s

~6,5 s

Native sehr deutlich schneller

Die absoluten Zeiten stammen aus unterschiedlichen Benchmarkformen und sind deshalb keine reine Mikrobenchmark-Ratio. Die Aussage bleibt: PSQL ist funktional und bei einfachen Aufgaben durchaus schnell; native UDRs skalieren bei intensiver Berechnung erheblich besser.

9. Der erste C++-gegen-Pascal-Vergleich

Die erste FPC-Version verwendete UnicodeString, UnicodeUpperCase und allgemeine Stringoperationen. Die C++-Version arbeitete dagegen weitgehend direkt auf UTF-8-Bytes. Im ersten Test erschien C++ dadurch teilweise vier- bis fünfmal schneller.

Das war kein fairer reiner Compilervergleich: Die Implementierungen verrichteten intern unterschiedlich viel Arbeit.

10. Den Vergleich fair machen

Die FPC-Version wurde auf denselben Low-Level-Ansatz umgebaut: UTF-8 bleibt im Hot Path byteorientiert, deutsche Sonderzeichen werden über ihre UTF-8-Sequenzen normalisiert, ASCII-Großschreibung erfolgt direkt, temporäre Stringoperationen werden reduziert und Cologne/Levenshtein verwenden kompaktere Buffer.

Die SQL-Schnittstelle und die Ergebnisse blieben unverändert.

11. Optimierungseffekt in Free Pascal

Funktion

FPC ursprünglich

FPC Fast UTF-8

Beschleunigung

SOUNDEX

~136 ms

~40 ms

~3,4×

SOUNDEX_DE

~79 ms

~47 ms

~1,7×

COLOGNE_PHONETIC

~152 ms

~43 ms

~3,5×

COLOGNE_DISTANCE

~269 ms

~62 ms

~4,3×

PHONETIC_SIMILARITY

~271 ms

~62 ms

~4,4×

Der größte Performancegewinn entstand also ohne Wechsel der Programmiersprache.

12. Optimiertes FPC versus Visual C++

Funktion

Visual C++ 2022

Optimiertes FPC

C++-Vorsprung ungefähr

SOUNDEX

~34 ms

~40 ms

~18 %

SOUNDEX_DE

~38 ms

~47 ms

~24 %

COLOGNE_PHONETIC

~38 ms

~43 ms

~13 %

COLOGNE_DISTANCE

~51 ms

~62 ms

~22 %

PHONETIC_SIMILARITY

~52 ms

~62 ms

~19 %

Mit vergleichbarer Implementierung schrumpfte der Abstand von scheinbar Faktor vier oder fünf auf typischerweise etwa 10 bis 25 Prozent.

13. Warum Lazarus nur Firebird.pas benötigt

Die Object-Pascal-Anbindung an Firebird ist für den Entwickler kompakt. Firebird.pas bündelt die wesentlichen Interfaces und Typdeklarationen in einer Pascal-Unit. Dadurch bleibt ein kleines Lazarus-UDR-Projekt übersichtlich und für Delphi-/Lazarus-Entwickler vertraut.

14. Warum Visual Studio mehr Header benötigt

Die C++-UDR verwendet Firebirds C++-Hilfsinfrastruktur mit UdrCppEngine.h, Message.h, Interface.h, ibase.h und weiteren Include-Dateien sowie Preprocessor-Hilfen.

Das sind überwiegend Compile-Time-Abhängigkeiten. Die fertige DLL benötigt nicht einfach alle diese Header zur Laufzeit. Pascal bündelt viele Deklarationen in einer Unit; C++ verteilt die API stärker auf Header, Templates und Makros.

15. Windows und Linux

PSQL ist innerhalb der Datenbank plattformneutral. Native UDRs müssen für die Zielplattform gebaut werden: typischerweise DLL unter Windows und Shared Library unter Linux. Der SQL-Vertrag kann gleich bleiben, die Binärdatei muss jedoch zu Betriebssystem, Architektur und Firebird-Server passen.

16. Praktische Entscheidung

Für moderate Aufrufzahlen und maximale Einfachheit ist PSQL attraktiv. Für hohe Aufrufzahlen oder rechenintensive Algorithmen bietet eine native UDR deutliche Vorteile.

Wenn bereits Delphi-/Lazarus-/FPC-Know-how vorhanden ist, gibt es nach unseren Messungen keinen Grund, allein aus Performance-Angst auf C++ zu wechseln. C++ bleibt ebenso eine ausgezeichnete Wahl, wenn entsprechende Erfahrung und Build-Infrastruktur vorhanden sind.

17. Die wichtigste Erkenntnis

Ausgangspunkt war die Frage, wie klassische Firebird-UDF-Funktionalität unter Firebird 5 sinnvoll modernisiert werden kann. Daraus entstand ein Vergleich von UDR und PSQL und schließlich ein direkter Test von Free Pascal und Visual C++.

Die wichtigste Erkenntnis ist nicht eine einzelne Millisekundenzahl: Architektur, Algorithmus und Datenrepräsentation dominieren häufig die Wahl der Sprache. Unsere erste Pascal-Implementierung war korrekt, verwendete aber komfortable allgemeine Unicode-Abstraktionen. Die C++-Implementierung arbeitete näher an den tatsächlich benötigten Bytes und war zunächst dramatisch schneller. Nachdem dieselben Prinzipien auf Free Pascal übertragen wurden, verschwand der größte Teil des Unterschieds.

Für Entwickler, die seit vielen Jahren mit Delphi oder Free Pascal arbeiten, ist das bemerkenswert: Gut geschriebener Pascal-Code ist auch heute konkurrenzfähiger nativer Code. Visual C++ blieb in unserem Test etwas schneller, aber der verbleibende Abstand lag eher im Bereich von etwa 10 bis 25 Prozent als bei Faktor vier oder fünf.

Gleichzeitig hat Firebird PSQL positiv überrascht. Nicht jede Funktion rechtfertigt eine native Bibliothek. Einfache phonetische Funktionen können als Stored Function eine attraktive Kombination aus Performance, Wartbarkeit und problemloser Verteilung bieten. Native UDRs werden dort besonders interessant, wo hohe Aufrufzahlen und komplexere Berechnungen zusammenkommen.

Die praktische Schlussfolgerung lautet deshalb: Zuerst den richtigen Algorithmus und die richtige Datenrepräsentation wählen, dann die passende Deployment-Strategie entscheiden – und erst danach die Programmiersprache als Performancefaktor bewerten.

18. Demo-Projekte und Reproduzierbarkeit

Die vollständigen Quelltexte werden bewusst nicht im White Paper abgedruckt. So bleibt das Dokument auch für Entscheider und Anwender lesbar.

Demo-Projekte für Firebird PSQL, Lazarus/Free Pascal und Visual Studio/C++ können auf Anfrage bereitgestellt werden. Benchmarkwerte sind Momentaufnahmen: Hardware, Firebird-Version, Compileroptionen, Datenverteilung, Cache-Zustand und Serverlast beeinflussen absolute Zeiten. Reproduzierbare Testdaten, identische Ergebnisse und mehrere Messläufe sind deshalb wichtiger als eine einzelne Bestzeit.