Das alte Spiel: RDBMS vs OOP unter dem Aspekt “Verteilbarkeit”

Der “Impedience Mismatch” ist einfach nicht totzukriegen. Ein meinerseits eigentlich sehr geehrter Professor behauptete einmal, dass dieser “Impedience Mismatch” bereits behoben wurde, als die ersten Datenbanktreiber entwickelt wurden (und dies machte dieser Professor bereits in den späten Siebzigern für ORACLE, wahrscheinlich für eine bereits vergessene Programmiersprache). Aber man wird mir zustimmen, wenn ich meine, dass dies so doch nicht der Fall ist und immer noch eine große Lücke klafft, die man mit Konstrukten, wie RDMS Gateways (aka “DAO”, aka “DAL”, aka “Repository”) oder einem richtigen O/R Mapper und natürlich mit LINQ überbrückt.

Viele denken heutzutage, dass das relationale Paradigma nicht so viel kann, wie die wahre Objektorientierung und doch ist der Marktanteil der relationalen Datenbanksystemen überwältigend.

Der Vorteil der RDBMS liegt nicht in einem höherwertigen Paradigma, sondern weil dessen Implementierung mittels SQL-Schnittstellen besonders gut in einer verteilten Umgebung (Client/Server) funktioniert.

Bei der Ausführung eines Queries wird nur ein Ergebnis zurückgegeben. So werden prinzipiell nur 2 Requests ausgeführt. Dies ist extrem wichtig, weil Netzwerklatenzen für die Performance eine große Rolle spielen und viele kleine Requests immer eine schlechtere Performance haben, als ein großer Request. Ein bekanntes daraus resultierendes Antipattern ist “Cripple Loading”, welches von Martin Fowler beschrieben wurde.

Ein Problem im SQL ist, dass das Ergebnis immer nur “flach” ist, d.h. um eine Objektstruktur abzufragen, benötigt man zumindestens mehrere Queries, die in einem Batch ausgeführt werden müssen. Eine Alternative sind XML-fähige DBMS wie SQL Server, die mittels Subqueries eine Baumstruktur zurückgeben können. Allerdings ist die Definition des Queries eher unförmig und sollte eher als ein Workaround eingesetzt werden.

Jetzt klang es fast so, als hätten SQL-Datenbanken ein Performanz-Problem wenn es um Verteilung geht. Wir werden eines Besseren belehrt, wenn wir O/R Mapper betrachten.

Der größte Vorteil von OO-Plattformen und Programmiersprachen ist die typisichere Referenz und natürlich die Polymorphie. Vielleicht war es ja C++, dass zu dem Missverständnis geführt hat, dass “Referenz” ein nettes Wort für einen “Zeiger” ist, also eine Adresse im Hauptspeicher. Obwohl das technisch natürlich für .NET gar nicht mehr stimmt (da gibt es ja eine Zwischentabelle, aber ich schweife ab…). So wären Referenzen natürlich erst einmal nur innerhalb eines Prozesses gültig. Weiterhin nimmt man als OO-Programmierer an, dass Objektreferenzen extrem schnell aufgelöst werden können  – schließlich liegen sie im Hauptspeicher und benötigen keine “Setup-Costs”.

Tja hier liegt das Problem mit der Verteilung: hier geht es nicht schnell.

Naive lazy-loading O/R Mapper (natürlich gibt es heute viel intelligentere!) bieten das beste Beispiel für jämmerliche Performanz bei den einfachsten Aufgaben, wie einen Baum zu navigieren und vielleicht in einer UI zu rendern.

Ich weißt nicht, wie viele Entwickler sich dessen bewusst sind, allerdings habe ich seit langem die Meinung, dass “RDBMS vs. O/R Mapper” ein “War of Mind” ist. Jede Kriegspartei denkt, dass sie überlegen ist. Lustig finde ich in diesen Zusammenhang, dass ich selten von einem fanatischen O/R-Gegner die wahren Gründe für die schwache Performance (meistens das Cripple Loading) von  Hibernate & Co in Blogs lese. Die RDBMS-Fanatiker fühlen sich bestätigt, aber kennen sie überhaupt den wahren Grund für die Performance-Probleme der Gegener?

Einen guten Eindruck dieses Kriegs vermittelt ein Post “The Vietnam of Computer Science”, der leicht zu googlen ist.

Ich persönlich denke, dass SQL auch mit Objekt-relationalen Erweiterungen nicht ausreichend für komplexe Anwendungen ist. Andererseits ist es gleichermaßen dümmllich, blind auf primitive OO-Paradigmen (die schnelle Referenz) zu vertrauen und einfach die Grundregeln der Verteilung zu ignorieren.

Eine Lösung will und kann ich gar nicht präsentieren. Aber die Essenz ist: Es wird dauernd vom Impedience Mismatch geredet, dabei ist dieser auf logischer Ebene doch gar nicht so groß. Primitivste O/R Mapper würden unter entfernen des Performance-Aspektes perfekt funktionieren.

Die ideale Lösung wäre, wenn jemand eine sprachbasierte Abstraktion implementieren würde, mit der eine performante verteilte Objektnavigation möglich ist, die sowohl für in-Memory, als auch persistente Datenspeicher anwendbar ist.

Denn Techniken wie LINQ sind schick (z.B. die Symbolintegration, d.h. Refactoring-sichere Queries), aber das grundlegende Problem der Verteilung wird nicht ausreichend gelöst.