Susanne: Ein Riesen-Join oder eine Handvoll kleine Züge?

Guten Morgen, eine theoretische Frage, vermutlich sogar eine des Geschmacks:

Gegeben sei eine Datenbank mit wenigen Tabellen und, im Vergleich dazu, teils vielen Daten. Bestimmte Daten soll ausgegeben werden, bei der Ausgabe werden immer Daten aus allen Tabellen benötigt. Da sich vielleicht die Datenbank oder Datenbankstruktur ändert, soll eine Funktion die Daten einsammeln, eine zweite Funktion soll sie zur Ausgabe aufbereiten.

Als Beispiel hat ein Zoo vier Tabellen, Tiere, Gehege, Angestellte, Fütterungen. Eine Ausgabe würde etwa die Fütterungen der letzten Woche sein, dazu brauchen wir die Tiernamen aus Tiere, den Ort aus Gehege, die Fütterungszeit, -art und -menge aus Fütterungen und natürlich den Namen desjenigen, der den Löwen den Löwenzahn gegeben hat, aus Angestellte.

Was ist nun sinnvoller: Eine Abfrage mit join über vier Tabellen, die sämtliche Daten auf einmal liefert, allerdings auch haufenweise Daten in tausendfacher Ausführung, die alle aufwändig zusammengeführt werden müssen (der Zoo hat nur drei Angestellte, aber 5.000 Ameisen, die alle einen Namen haben und liebevoll einzeln gefüttert werden), oder vier Abfragen an die jeweiligen Tabellen auf die Gefahr hin, dass sich zwischen den zusammengehörigen Abfragen eine Tabelle ändert (die Tiere sterben wie die Fliegen, insbesondere die Fliegen) und die gesammelten Daten insgesamt nicht mehr stimmig sind?

Welchem Aspekt sollte grundsätzlich mehr Beachtung geschenkt werden, der Datenmenge oder der Stimmigkeit? Ich denke eigentlich letzterem und damit der join-Variante, frage mich aber, wo wohl die Grenze zu ziehen wäre. Wenn die Datenbank oder die Funktionen tatsächlich merklich in die Knie gehen?

Danke, Susanne

  1. Tach!

    Was ist nun sinnvoller: Eine Abfrage mit join über vier Tabellen, die sämtliche Daten auf einmal liefert, allerdings auch haufenweise Daten in tausendfacher Ausführung, die alle aufwändig zusammengeführt werden müssen [...] , oder vier Abfragen an die jeweiligen Tabellen auf die Gefahr hin, dass sich zwischen den zusammengehörigen Abfragen eine Tabelle ändert [...] und die gesammelten Daten insgesamt nicht mehr stimmig sind?

    Es gibt auch noch Alternativen zu Joins. Zumindest, wenn aus einer Tabelle nur ein einzelnes Feld benötigt wird, kann man da eine correlated subquery verwenden. Nicht nur, dass man damit die beiden Querys auch einzeln testen kann, man vermeidet den Join und die Kopfschmerzen damit. Und man hat die Subquery schön übersichtlich an einem Fleck. Beim Join hingegen steht das Feld in der SELECT-Klausel und die Datenquelle irgendwo weiter hinten in der FROM-Klausel.

    Welchem Aspekt sollte grundsätzlich mehr Beachtung geschenkt werden, der Datenmenge oder der Stimmigkeit? Ich denke eigentlich letzterem und damit der join-Variante, frage mich aber, wo wohl die Grenze zu ziehen wäre. Wenn die Datenbank oder die Funktionen tatsächlich merklich in die Knie gehen?

    Was nützen dir schnelle Daten, wenn sie falsch sind? Korrekte Daten mit viel Wartezeit mag aber auch keiner. Korrekt und optimiert, ist das, was man haben möchte. Indexe passend setzen, Analysewerkzeuge verwenden (zum Beispiel EXPLAIN bei MySQL).

    dedlfix.

    1. Die correlated Subquery ändert aber nichts an dem Umstand, dass sie für jede einzelne Ameise und vor allem Fliege den Namen des zugehörigen Wärters in der Ergebnismenge hat.

      Damit eine historische Query funktioniert, brauchst Du historisierte Tabellen. Wärter Nr 5 darf nicht am Montag der Klaus und am Mittwoch die Claudia sein (es sei denn, er war am Dienstag beim Chirurgen). Wenn das Ameisengehege am Dienstag die ID 7 hat und am Donnerstag die ID 9 (weil die Tierchen am Mittwoch umgezogen sind), kann eine retrospektive Auswertung merkwürdig aussehen, wenn Du auf einmal 5000 Elefanten im Ameisengehege mit bestem Aas-Granulat fütterst (die Fliegen-Nahrung).

      Da die Sterblichkeit der Wärter sicherlich gering ist und die Gehege vermutlich auch nicht so oft ihren Platz wechseln, KÖNNTEST Du in zwei vorauslaufenden Abfragen erstmal alle relevanten (sprich: historisch für den Auswertezeitraum gültigen) Wärter und Gehege in Arbeitstabellen deines Auswerteprogramms laden. Und dann machst Du einen Join auf Tiere und Fütterungen, um die Fütterung jeder einzelnen Ameise und Fliege zu bekommen. Bei den Tieren findest Du die Gehege-ID, bei den Fütterungen die Wärter-ID desjenigen, der gefüttert hat, und suchst Dir den historisch richtigen Satz aus den vorgeladenene Tabellen dazu. Für die Ausgabe kannst Du dann z.B. nach Tierart gruppieren, die Tierart als Überschrift ausgeben, darin die Tiere und für die Tiere eine Unterzeile pro Fütterung. In die Fütterungen kannst Du an Hand der ID den Namen des Wärters einstreuen.

      De facto wirst Du sicherlich was anderes tun wollen, aber von der Idee her kann das so gehen.

      Wenn Du Sorge hast, dass sich Tabellen während des großen Join ändern, brauchst Du eine Transaktion um das Ganze mit einem entsprechenden Isolationslevel. Siehe Datenbankhandbuch...

      Rolf

      1. Tach!

        Die correlated Subquery ändert aber nichts an dem Umstand, dass sie für jede einzelne Ameise und vor allem Fliege den Namen des zugehörigen Wärters in der Ergebnismenge hat.

        Ich wüsste nicht, wie man das wegbekommt. Wenn man das nicht in der Abfragemenge hat, dann entsteht die Datenverdopplung halt nicht schon im DBMS sondern erst bei der Ausgabe der Daten. Das entlastet vielleicht den Teil zwischen DBMS und abfragendem Programm, aber belastet dafür Letzteres.

        Wenn Du Sorge hast, dass sich Tabellen während des großen Join ändern, brauchst Du eine Transaktion um das Ganze mit einem entsprechenden Isolationslevel.

        Wenn das der Fall sein kann, hat man ein anderes Problem. Selbst wenn die Daten konsistent abgefragt wurden, verlieren sie an Wert, weil sie zwischen Abfrage und Betrachten veraltet sind.

        dedlfix.

        1. Die Anfrage von Susanne bezog sich auf die Datenbank. Wenn man da den Traffic reduzieren will, kann das Vorauslesen von Lookup-Tabellen helfen. Dass die Durchführung des Lookup den Webserver stärker belastet, ist natürlich richtig. Das hängt aber auch von der gewählten Datenstruktur ab (Dictionary, sequenziell durchwühltes Array, EAV Konstrukt...). Es entlastet beim Server aber auch die Menge des belegten Speichers für den Request (es sei denn, man puffert das Abfrageergebnis der Monsterquery nicht).

          Zum Thema Historie: Das muss man je nach Fall betrachten. Historisch abgelaufen heißt nicht unbedingt veraltet. Es ist ja durchaus möglich, dass die Ameisen am Mittwoch im "Haus 5" gefüttert wurden und ab Donnerstag 15:00 im "Haus 9". Pro Fütterung kann die Konsistenz also durchaus gegeben sein. Jedenfalls ist das besser, als treu zu berichten, dass die Ameisen von Montag bis Freitag im Haus 9 gefüttert worden seien. Die Frage, warum es überhaupt relevant ist, das zu berichten, beantwortet sich ganz einfach so: Die Ameisen sind ins Haus 9 gezogen, aber da sind auch schon die Puhbären. Und bekanntlich reagieren die ganz wild auf Honig. Seit die Ameisen da mit ihren Honigtröpfchen gefüttert werden, gibt es bei den Puhs immer wieder Fälle von gebrochenen Nasen, weil die blöden Biester zu den Ameisen rennen wollten und gegen die Glasscheibe geprallt sind. Anhand der exakten Dokumentation kann man nun den Zusammenhang nachweisen.

          Wie die konkrete Lösung aussieht, muss Susanne an Hand ihres realen Modells und Sachverhaltes analysieren. Am Zoobeispiel können wir nur die möglichen Probleme aufzeigen.

          Rolf

          1. Hallo,

            Die Ameisen sind ins Haus 9 gezogen, aber da sind auch schon die Puhbären.

            Hätte man nun aber statt Puhbären Ameisenbären, hätte man auch gleich das Problem mit der Fütterung gelöst...

            Gruß
            Kalk

            1. Auch das hätte die exakte Dokumentation wiedergegeben. Ab Donnerstag 15:00 nimmt der Honigtröpfchenbedarf für die Ameisen schlagartig ab. Und die Ameisenbären scheinen auf einmal seltsam appetitlos und mögen ihr Ameisengranulat nicht mehr.

              :) Rolf

              1. Hallo,

                die Ameisen sind leider erfroren, wir steigen jetzt auf Zettel und Stift um. Das ist auch besser für unsere Wärter, weil die alle über 90 sind, ist uns neulich der Elefant verhungert, der Vielfraß.

                Wie ich schon vorweggeschickt hatte, war die Fragestellung sicher zu weit gefasst, um mehr als eine Einschätzung, den persönlichen Geschmack abgeben zu können. Eure Antworten haben mich aber darin bestärkt, die Datenintegrität an erste Stelle zu setzen und getreu dem Motto Premature optimization is the root of all evil erstmal zu gucken, wie sich das Gesamtsystem tatsächlich verhält.

                Und dann die Spätschäden, an denen ich leide! Mein Unterbewusstsein misst "große Datenmenge" trotz therapeutischer Maßnahmen noch in Heimcomputergrößen, bei allem über 512 KByte kriege ich Herzrasen ...

                Danke nochmal.