Datenbanklogik



  • Tag zusammen,

    ich bin kein Datenbank Experte, mich würde da mal etwas interessieren:

    Gewöhnlich hat ein Programm ja eine Architektur, eine Aufteilung wie z.B. MVC oder Schichten mit jeweils verschiedenen Verantwortungen. Bleiben wir ruhig mal im MVC, damit wir vom gleichen sprechen, die Prinzipien sollten überall gleich sein, denke ich.
    So, nun will mein Programm ja irgendwo irgendwann auf Daten zugreifen, die es entweder selbst erzeugt und dann in die Datenbank schreibt oder eben von dort aus ausliest.

    Mein Frage ist jetzt:
    Wie viel Logik gehört in mein eigenes Programm, sprich in meine Datenbankklassen, und wie viel in die Datenbank selbst.
    Denn rein theoretisch könnte man ja sich jeweils sehr kurze SQLs schreiben, die die Daten einer Tabelle holen und abhängig davon jeweils wieder separate SQLs los schiessen, die referenzierte Tabellen holen.
    Gegenteilig wäre, dass man ein (grösseres) SQL losschickt, welches einem direkt die gesamten Datensätze hergibt.

    Was ist die eine Best-Practice?
    Wo sind die Grenzen?
    Was sind Anti-Patterns?

    Natürlich habe ich mal Onkel Google befragt und bin da darüber gestolpert, dass man jeweils dort etwas nutzen soll, wo das System auf eben diese Nutzung optimiert ist. D.h. rechnen im Programm, DaAten holen und filtern in der Datenbank(-System).
    Aber gerade mit so Dingen wie dem .NET LINQ oder eben Stored Procedures weerden solche Grenzen ja aufgeweicht. Der eine sagt dann "Nix Datenbank, das machen wir im Programm, dann sind wir nicht an ein DBMS gebunden" und der andere sagt "Nix Programmlogik, das machen wir im DBMS, dann sind wir nicht an irgendwelche Programmiersprachen und -umgebungen gebunden"

    Ich persönlich würde einen güldenen Mittelweg als gut ersehen, so dass die Programmlogik nicht unnötig aufgebläht wird durch Filter- und Mengenoperationen, aber auf der anderen Seite auch keine seitenlangen SQLs nötig sind (das hab ich vor einiger Zeit in der Firma gesehen und bin immer noch schockiert, zu Recht?).

    Und dann gibts da ja noch so moderne Technologien wie JPA, Hibernate etc. (kenne da nur Java Dinge), die selbst schon ein Objekt-Relationales Mapping vollziehen und damit, wie ich finde, einen in Richtung Programmlogik schubst.

    Übersehe ich vielleicht etwas? Oder fehlt mir Erfahrung?

    Viele Grüße,
    Skym0sh0



  • Ja, du übersiehst mindestens noch die Stored Procedures, die alles noch verkomplizieren 🙂



  • So wie ich das sehe, ist es im Oracle Umfeld mehr oder weniger üblich, sehr viel Logik in die Datenbank zu stecken. Nicht nur über "größere" SQL Statements, sondern da wird praktisch die gesamte Logik und Verarbeitung als Stored Procedures geschrieben. Ich kenne mich in der Ecke aber auch nicht aus, hatte mit solchen Anwendungen nichts zu tun. Ich habe früher das Oracle Magazine gelesen und in meiner Datenbank Vorlesung ging es auch in die Richtung. Der Prof hatte viel mit großen Oracle Projekten zu tun und für ihn wars irgendwie selbstverständlich, dass die Datenbank die gesamte Logik enthält.
    Ich weiß nicht, inwiefern das jetzt tatsächlich stimmt, aber mir persönlich gefällt so ein Ansatz nicht. Mir ist eine Schichtenarchitektur mit Frontend, Application Server (oder von mir aus Micro Services) und Datenbank als dummes Backend lieber.
    In diesem Kontext ist deine Frage eigentlich irrelevant. Und da spielen eigentlich ganz andere Kriterien eine Rolle. Du musst fast immer die Datenbank möglichst viel machen lassen, und zwar wegen der Performance. Wenn du selber auf referenzierte Tabellen zugreifst, ist es viel langsamer als ein Join. Jede Anfrage erhöht die Latenz, da bist du schnell Faktor 1000 langsamer. Dann das ganze Caching, Query Optimizing und tausende andere Technologien, die Datenbanken bieten... Dann fängt man irgendwann doch an, etwas Logik in die Stored Procedures zu packen, weil sie in der Datenbank laufen. Aber vielleicht nicht ganz so viel Logik, wie im Oracle Umfeld üblich. So pauschal kann man die Frage also nicht beantworten, man muss sich da schon auskennen und sich die Anforderungen und die Rahmenbedingungen genau anschauen und dann evaluieren.



  • Das kommt für mich stark drauf an ob man eine Applikation baut die so richtig an Kunden ausgeliefert wird, wo es also Installationsprozesse und Updates etc. gibt, oder ob man eine "in house" Lösung entwickelt die an einem einzigen Standort läuft und aus.

    Bei zu installierenden und upzudatenden Applikationen tendiere ich dazu quasi alles in der Applikation zu machen.

    Allerdings so, dass ich durchaus grössere SQL Statements baue.
    Wobei "grösser" auch gerne mal ein paar hundert Zeilen sein kann. Wenns zu gross für String-Literale wird (weil unübersichtlich), dann landet der Code in einem .sql File. Was dann entweder einfach so als File neben der .exe liegt, oder auch mal in einer Resource im .exe File.

    Die Ausnahme wären vielleicht Views -- wobei ich bei solchen Applikationen noch keine Views gebraucht habe. Wenn nötig packe ich halt ne Common Table Expression in einen String, so dass ich das Ding einfach vor ein SELECT dranpappen kann ohne den Code überall zu wiederholen.

    Vorteil ist u.A. dass man bei Updates viel seltener Änderungen in der Datenbank machen muss. Dadurch werden die Installer viel einfacher, und wenns mal sein muss kann man auch einfacher ein Downgrade machen. (So lange sich an der Tabellenstruktur bzw. impliziten Constraints(*) nichts geändert hat kann man einfach eine alte Softwareversion gegen die aktuelle Datenbank laufen lassen, weil eh der ganze Code in der Applikation ist.)

    Bei Applikationen die bloss an einem Standort laufen ist meine Erfahrung dagegen dass man wild mischt und alles dort macht wo man es am einfachsten umsetzen kann. Bzw. wenn Performance eine Rolle spielt: dort wo es am schnellsten läuft, bzw. halt wo die "Performance vs. Entwicklungszeit" Abwägung am besten aussieht.

    Das ist vom Standpunkt des Softwareentwicklers sicher nicht optimal, aber von unternehmerischen Standpunkt aus betrachtet vermutlich gar nicht schlecht.
    Nur dass man mischt heisst ja nicht dass man deswegen einen kompletten Sauhaufen zusammenprogrammieren muss 🙂

    Und, was auch wichtig sein kann: man kann, wenn man akzeptiert bestimmte Dinge direkt in der DB zu machen, oft den Ball sehr flach halten. z.B. sind ON UPDATE Trigger ein Segen wenn man Änderungen an bestimmten Daten erfassen möchte. Oder man kann aus einem Web-Frontent direkt in bestimmte Tabellen schreiben, ohne dass man für jede Kleinigkeit einen Aufruf im dafür zuständigen Service machen muss.

    Ab einer bestimmten Grössenordnung kann sowas natürlich auch zu Problemen führen. Eine Silver Bullet gibt es aber nicht. Time To Market ist immer ein grosser Faktor, oft der Faktor neben dem alles andere verblasst. Und wenn man mal so richtig richtig gross ist, und eine richtig schön unübersichtliche Sauhaufenapplikation hat, dann macht man hoffentlich auch so viel Umsatz dass man es sich leisten kann alles ganz grob zu refactoren bzw. ein "Generation 2" System zu entwickeln. Oder man guckt dass man sich als Firma von irgendwem kaufen lassen kann der nur den tollen Umsatz und die vielen tollen Funktionen des Systems sieht, aber keine Ahnung hat wie unwartbar und furchtbar das Ding intern ist 😃 🤡

    (*): Mit "impliziten Constraints" meine ich "Regeln" die nicht in der DB als z.B. CHECK/NOT NULL/DEFAULT/... Constraints umgesetzt sind, sondern einfach von der Applikation forciert werden. Bei einer Änderung solcher Regeln kann es natürlich trotz identischer Tabellenstruktur Probleme beim Downgrade geben. Nämlich wenn eine neuere Version nach Daten in die DB geschrieben hat die zwar die neuen Regeln nicht verletzen, aber die alten sehrwohl.



  • Also ich habe hauptsächlich mit SAP (diese C++-Welt ist für mich neu) zu tun, ein monströses tabellengesteuertes ERP-System mit zig tausenden Tabellen und Views, der erste Focus gilt also der Beschaffung der Daten. Wenn man es erstmal mühsam geschafft hat alle benötigten Tabellen und deren Verbindungen zusammenzusuchen hängt die Realisierung weitestgehend von der Anforderung ab:

    Für den Batchbetrieb (Reports, Massenupdates usw.) werden oft viele oder alle Daten auf einmal zusammengelesen und in einem Stück verarbeitet (man packt sie in "interne Tabellen" was arrays entspricht und arbeitet mit denen weiter), wenn nötig müssen passende Indices aufgebaut werden, das muss von Fall zu Fall sehr sorgfältig geprüft werden. Die Programme laufen oft stundenlang, meist Nachts.

    Im Dialogbetrieb geht das so meist nicht, man muss die Daten stückeln und je nach Dialoganforderung des Users Folgedaten nachlesen.

    "Stored Procedures" und andere DB-nahe Zugriffe sind den Entwicklern i.d.R, nicht oder nur eingeschränkt zugänglich, manche Kunden untersagen den SQL-Zugriff komplett, es dürfen nur die extra programmierten und optimierten Zugriffsbausteine benutzt werden, vor der Übergabe in den Produktivbetrieb müssen bestimmte Lasttests bestanden werden denn die Datenbestände in großen Konzernen sind durch extrem viele Bewegungen und hohen DB-Normalisierungsgrad so gewaltig, dass SAP sich genötigt sah eine neuartige Datenverwaltung aufzubauen, mit der ich derzeit aber noch keine Erfahrungen habe und nichts dazu sagen kann.

    Jetzt habe ich durch das Gesabbel den Faden verloren und weiß nicht mehr was ich eigentlich zum Thema sagen wollte 😮



  • Naja, bei SAP ist die Sache mehr oder weniger klar: man macht es so wie SAP es will. Und das ist: alles in der Applikation (was in dem Fall ja SAP ist).

    SAP legt dann dynamoautomatisch Stored-Procedures an wenn es meint dass das von Vorteil wäre.
    Wobei ich mit dynamoautomatisch meine: SAP legt die automatisch an wenn es sie noch nicht gibt, und updated sie soweit ich weiss auch selbständig falls der SAP Code aus dem/für den sie erzeugt wurden geändert wird.



  • Das sind verdammt viele Fachbegriffe, die mir nix sagen, gerade im Beitrag von hustbaer oO

    deejey schrieb:

    Ja, du übersiehst mindestens noch die Stored Procedures, die alles noch verkomplizieren 🙂

    Die hab ich doch genannt...



  • hustbaer schrieb:

    Naja, bei SAP ist die Sache mehr oder weniger klar: man macht es so wie SAP es will. Und das ist: alles in der Applikation (was in dem Fall ja SAP ist).

    Das kann man so nicht sagen: Für die Datenbeschaffung stehen von SAP vordefinierte sog. "logische Datenbanken" zur Verfügung, die Daten je nach Hauptschlüssel hierarchisch (1:n-Beziehungen) zur Verfügung stellen. In den Fällen wo das für die Anforderung aber nicht passt muss man die Daten selbst lesen, vollständig in eigener Verantwortung, da greift SAP nicht ein.

    SAP legt dann dynamoautomatisch Stored-Procedures an wenn es meint dass das von Vorteil wäre.
    Wobei ich mit dynamoautomatisch meine: SAP legt die automatisch an wenn es sie noch nicht gibt, und updated sie soweit ich weiss auch selbständig falls der SAP Code aus dem/für den sie erzeugt wurden geändert wird.

    Also davon weiß ich nichts 🙄 vlt. läuft das im Data Warehouse/BI so, das ist eh eine Welt für sich



  • Skym0sh0 schrieb:

    deejey schrieb:

    Ja, du übersiehst mindestens noch die Stored Procedures, die alles noch verkomplizieren 🙂

    Die hab ich doch genannt...

    oh, sry



  • @deejey

    bei SAP gibt es aber nicht die Problematik das deine SQL-Syntax nicht 100% zwischen verschiedenen DBs passt - oder deine StoreProcedures in verschiedenen Sprachen z.B. T-SQL für Microsoft SQL-Server und PL/SQL für Oracle, oder PL/pgSQL bei PostgreSQL - und viele mehr

    bei SAP bleibt SAP immer deine Basis - oder?



  • Gast3 schrieb:

    @deejey

    bei SAP gibt es aber nicht die Problematik das deine SQL-Syntax nicht 100% zwischen verschiedenen DBs passt - oder deine StoreProcedures in verschiedenen Sprachen z.B. T-SQL für Microsoft SQL-Server und PL/SQL für Oracle, oder PL/pgSQL bei PostgreSQL - und viele mehr

    bei SAP bleibt SAP immer deine Basis - oder?

    Ja, aber nur so lange man das sog. "Open SQL" im ABAP durchgehend benutzt, für die Kompatibilität sorgt dann die untere Schicht und man muss sich keine Gedanken machen. Jedoch kann auch "native SQL" benutzt werden, das geht direkt an den DB-Server, Kompatibilität ist ungewiss.

    Dann gibt es noch so ein DB-spezifisches "HINT" was auch bei Open SQL wirkt, wenn man die DB zur Benutzung eines bestimmten Index zwingen will. Aber wie gesagt, manche Kunden untersagen den Entwicklern DB-spezifische Zugriffe.



  • Ich habe mittlerweile nicht mehr soviel verstanden, weil ich die Systeme alle nicht kenne oO

    Vielleicht kann ich die Diskussion etwas umlenken:

    Nehmen wir mal an, wir nutzen keine Businesslogic in der Datenbank, d.h. Stored Procedures werden nicht genutzt.

    Ist es jetzt besser (komplexe) Abfragen über die Datenbank zu machen oder sich lieber z.B. alle Daten geben zu lassen und dann selbst im eigenen Programm diese zu verarbeiten, z.B. mit LINQ in (C#).NET?

    Intuitiv würde ich sagen, Datenbanksysteme sind genau darauf optimiert, also sollten die das auch machen?!
    Umgekehrt würde ich denken, naja wenn man eine normalisierte Datenbank hat, dann können größere Objekterzeugungen ziemlich groß und komplex werden, da ja viele Tabellen gejoint werden (müssen).


  • Mod

    Erfahrung sagt: Es ist sehr lohnend, sich über diese Art Problematik seine Gedanken zu machen.

    Generell hängt es natürlich erstmal von der Datenbank (den Daten und dem Hintergrund selber ab) was sie können sollte und was nicht.
    Man kann aber auch generell sagen, dass Performance und Erweiterbarkeit schon eine wichtige Rolle spielen.

    Was man auch generell sagen kann, ist, dass eine Datenbanklogik immer auch einer Überlogik folgt, also z.B. Rechenwerk im Chip, Betriebssystem, Schulbildung usw.
    (siehe auch https://de.wikipedia.org/wiki/Lotus_1-2-3 , http://www.aresluna.org/attached/computerhistory/articles/spreadsheets/lotus123review (das Lotus 1 2 3 Programm wurde in Assembler geschrieben und war ziemlich schnell)
    (Ein wichtiges Feature von der Programmierprache Haskell ist "Lazy Evaluation". "Real World" Erfahrungen zeigen aber (z.B. Haskell Schrittweise erlernen, Serveranwendungen, dies und das, dass die (zugrundeliegende) Lamda-Logik zwar toll ist aber eben eher "ideal" denn "funktional" (??), http://community.haskell.org/~simonmar/slides/cadarache2012/5 - server apps.pdf , https://hackhands.com/lazy-evaluation-works-haskell/ )
    (viele Workarounds, Nachsitzstunden -> Lamba-Logik üben, um die wichtigste Grundlage besser (und intuitiver) zu verstehen und -> Assemblerschnittstelle finden und -> Parallelperformance nutzen, Wunschzettel: Datenbankoptimierung (mehr Dokumentation und Ordnung (plus Aussortierung eher fragwürdiger Einträge) (Real World Orientierung, Professionelle Programmierung) erforderlich).

    (ach so, hilft vielleicht: -> http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html )



  • Wie ich schon geschrieben haben, ist es aus Performancesicht meist besser, die Datenbank möglichst viel machen zu lassen. Wenn deine Anfragen dazu führen, dass du weitere Anfragen machen musst, hast du zusätzliche Round Trips - sehr schlecht. Ein Join ist da viel besser. Und die Datenbank kann die Anfragen viel besser cachen, optimieren usw., weil die Datenbankhersteller genau da viel Arbeit reingesteckt haben.



  • In der Regel sind DB seitige Abfragen performanter. Die DB muss ja alle Daten suchen und an den Client übertragen. Findet die Selektion/Auswertung erst im Client statt, müssen mehr Daten zusammengeschaufelt werden.

    Joins in der DB sind deutlich performanter als im Client.

    DB seitige Logic über Stored Proc´s hat den Vorteil, dass die Anfrage nicht jedes mal neu interpretiert werden muss. Bei Interpretation der Anfrage sucht die DB jedes mal einen optimalen Lösungsweg. Im Falle einer SP ist der Lösungsweg bereits hinterlegt.

    Bei einer Kapselung über SP´s als Schnittstelle arbeiten alle Progger Clientseitig mit den gleichen Daten. Sp´s haben benutzerdefinierte Rückgabewerte.

    Datenhaltung in einem Clientseitigen Dataset hat auch den Nachteil, dass die Daten nach Bearbeitung nicht mehr unbedingt konsistent sind. Also ein ganzes Dataset vollgepackt bearbeitet und zurückgespielt, inzwischen können aber woanders Änderungen erfolgt sein.

    Der Aufwand für DB Seitige Logic ist natürlich hoch. Bei einer Webseite mit DB auf dem gleichen Server würde ich aus Kostengründen ein Dataset vorziehen. Es kann auch Sinn machen zu mixen, gerade bei inserts und updates Sp´s zu verwenden für die Konsistenz.

    MS SQL kann neben SQL Sp´s noch , Tabel Funktions, Scalar Funktions, .Net Assemblies und lässt sich über extendet stored Proc´s als Dll erweitern. Aber fang nicht an mit Kanonen auf Spatzen zu ballern.



  • Skym0sh0 schrieb:

    Ist es jetzt besser (komplexe) Abfragen über die Datenbank zu machen oder sich lieber z.B. alle Daten geben zu lassen und dann selbst im eigenen Programm diese zu verarbeiten, z.B. mit LINQ in (C#).NET?

    Wenn Du mit LINQ das ohne TO SQL meinst, sind alle Abfragen mit einfachen
    Schleifen realisiert. Soweit habe ich das zumindest verstanden. Bei "LINQ to SQL"
    wird ein DB-Context angegeben, die Abfragen entsprechend formuliert und der
    Server führt dann das kompilierte Statement aus.

    Läßt Du Dir ganze Tabellen in DataSets zurückliefern und konkretisierts dann
    mit dem tollen LINQ deine Abfragen, Sorts, Joins usw. wird alles in Schleifen
    ohne irgendwelche Indexe realisiert !

    Kann m.M auch garnicht anders funktionieren, wenn Du eine Liste vom Typ
    erstellst. Da ist kein PK oder sonstwas definiert.



  • Ich bin mal wieder an dem Thema am knabbern und grabe deswegen diesen Thread von vor 7 Monaten nochmal aus.
    Meine Frage jetzt, und damals auch schon zum Teil, richtete sich in eine andere Richtung. Und zwar weniger, ob Logik in der Datenbank (ala Stored Procedures) oder in das Programm gehört, sondern vielmehr wie Datenbankanbindungen im Code aussehen.

    Annahme:
    Nehmen wir an, dass wir es eine Reihe von Anwendungen gibt (d.h. eine Umgebung mit mehreren Modulen) die auf einem Server läuft und logischerweise auch auf eine Datenbank zugreifen muss. Die Datenbank kann mal MySQL, mal MSSQL, mal SQLIte sein oder was auch immer. D.h. Stored Procedures wollen wir damit mal ausschließen. Vor allem weil das Datenbanksystem auch mal gewechselt werden kann/können soll.

    Ist es jetzt Best-Practice beim Modellieren einer Anwendung ein schönes ER-Diagramm aufzumalen (oder zu denken), das dann in der Datenbank umzusetzen (nehmen wir auch mal an ohne Foreign-Keys und ohne, dass sich das DBMS um Integrität kümmert bei normalisierten Tabellen*) und im Programmcode dann SQL-Statements zusammen zu setzen? (Können wir hier unterscheiden zwischen dem Low-Level String konkattenieren um eine SQL zu bauen und eine Abstraktionsebene wie JOOQ dazwischen zu setzen?!)

    Oder ist es besser, die Businessdaten als Klassen (z.B. im M vom MVC) zu modellieren und dann später eine Datenabstraktionsschicht (Stichwort DAO Pattern) dadrauf zu setzen?

    Mir ist klar, dass es da sicherlich keine Silver Bullet gibt. Gerade wenn Performance ins Spiel kommt, aber solche Fälle lassen sich eingrenzen, denke ich. Vielleicht können wir sogar mal konkrete Beispiele bauen.

    Um das nochmal zusammen zu fassen:

    - Keine Stored Procedures (weil verschiedene DBMS Ökosysteme)
    - Datenmodellierung nur in der Datenbank
    - Datenmodellierung im Code (Daten Klassen)
    - Datenbankzugriffe wegkapseln
        + DAO Pattern/Repository/ORM etc.
    - SQL im (Controller-) Code zusammenbasteln und feuern
    - Abstraktes SQL wie z.B. JOOQ im Client Code zusammenbasteln
    

    *: Ist das überhaupt eine sinnvolle Annahme? Oder könnte man dann gleich auf Datenbanksysteme scheissen und gute alte Textdateien nehmen?



  • Kann es sein dass du einfach nur ORM suchst?



  • Shade Of Mine schrieb:

    Kann es sein dass du einfach nur ORM suchst?

    Naja, das ist eben die Frage.

    Benutzt man das in der "großen" praktischen Berufswelt?
    Oder ist das mal eben für kleine (Uni-)Projekte ganz lustig, aber dann im Großen kaum wartbar?



  • Das benutzt man in der "großen" praktischen Enterprise Welt.

    Abseits von Enterprise aber dann etwas weniger. Wir machen jetzt nicht so viel mit Datenbanken in der Arbeit, haben aber auch eine Datenbankanbindung in unserer Software. Man könnte wahrscheinlich schon irgendwie ORM reinbringen... Bietet sich aber nicht wirklich an. Kaum irgendwelche üblichen Record- oder Objektbasierten Abfragen und Aktualisierungen, dafür viele völlig unterschiedliche Abfragen. Abstraktionsschichten haben wir natürlich drin, aber kein ORM.


Log in to reply