Alex: /(DATENBANK): Flexible Grundstruktur

Hallo alle zusammen.

Ich kaue gerade auf der Frage herum, wie eine möglichst flexible DB-Grundstruktur eines kleinen CMS aussehen müßte. Folgendes habe ich mir überlegt:

Position und Hierarchieren der Einzelseiten werden über eine Baumstruktur festgelegt, in der jede Seite einfach nur ein Knoten ist. Dieser Baum existiert also einzig, um die Gesamtstruktur des Systems abzubilden. Ob der intern nun über Parent-Child-Modell oder eher Nested Sets realisiert wird, soll für die einzelnen Seiten keine Rolle spielen. Diese können dann nämlich davon unabhängig Artikel, Bildergalerie, Kontaktformulare, Kategorien (zum Gruppieren zusammengehöriger Seiten) oder sonstwas sein -- jede mit einer eigenen Funktionsweise und anderen Daten, die für den Betrieb wichtig sind. Für jeden dieser Typen gibt es in der DB also auch einen eigenen Typ von Tabelle, in der -- als kleinster gemeinsamer Nenner -- jeweils eine Knoten-ID gespeichert ist. Adressiert werden sollen die Seiten dann ausschließlich über diese Knoten-ID (z.B. innerhalb der Navigation).

Das find ich prinzipiell schonmal nicht verkehrt, allerdings stört mich etwas daran. An der Stelle, wo die zu einem Knoten gehörige Seite gefunden werden soll, muß ich quasi mit allen vorhandenen Typen von Seitentabellen vergleichen, ob ein Eintrag mit bestimmter Knoten-ID existiert. Das wird also ein ziemlich großer JOIN, in dem alle möglichen Tabellen vorkommen -- eben so viele, wie unterschiedliche Seitentypen existieren. Ich könnte die benötigte Query dynamisch aus allen "bekannten" Tabellennamen zusammensetzen, dann muß ich bei Ergänzungen neuer Seitentypen zumindest nicht die jedesmal von Hand die Query umschreiben. Trotzdem wächst bei solchen Ergänzungen dieses JOIN-Gebilde immer und immer weiter. Außerdem muß ja irgendwie vermerkt werden, in welcher Tabelle nun die gesuchte Knoten-ID gefunden wurde.

Das scheint mir insgesamt nicht so gut zu skalieren. Wie könnte man das System strukturieren, um dieses Problem zu vermeiden? Ist das Ganze vielleicht schon im Ansatz etwas unglücklich geraten?

Grüße von Alex

  1. Hallo

    Ich kaue gerade auf der Frage herum, wie eine möglichst flexible DB-Grundstruktur eines kleinen CMS aussehen müßte. Folgendes habe ich mir überlegt:

    [...] Diese können dann nämlich davon unabhängig Artikel, Bildergalerie, Kontaktformulare, Kategorien (zum Gruppieren zusammengehöriger Seiten) oder sonstwas sein -- jede mit einer eigenen Funktionsweise und anderen Daten, die für den Betrieb wichtig sind. Für jeden dieser Typen gibt es in der DB also auch einen eigenen Typ von Tabelle,

    Es ist keine gute Idee, für Neues "neue Tabellen" oder auch nur "neue Spalten" anlegen zu wollen.

    Das scheint mir insgesamt nicht so gut zu skalieren. Wie könnte man das System strukturieren, um dieses Problem zu vermeiden? Ist das Ganze vielleicht schon im Ansatz etwas unglücklich geraten?

    Ja, ist es. Du solltest im Normalfall mit neuen Zeilen auskommen und nicht an der DB-Struktur herumschrauben müssen, wenn Neues hinzukommt.

    Freundliche Grüße

    Vinzenz

    1. hi,

      Du solltest im Normalfall mit neuen Zeilen auskommen und nicht an der DB-Struktur herumschrauben müssen, wenn Neues hinzukommt.

      Dann hat man doch wieder das Problem, dass die Tabellen zu überladen sind.
      Wie steht es da um die Normalisierung?

      mfg

      1. Hallo

        Du solltest im Normalfall mit neuen Zeilen auskommen und nicht an der DB-Struktur herumschrauben müssen, wenn Neues hinzukommt.

        Dann hat man doch wieder das Problem, dass die Tabellen zu überladen sind.

        Wieso? Soundsoviele Datensätze, ja und? Dazu ist eine Datenbank da.

        Wie steht es da um die Normalisierung?

        Was hat die mit der Anzahl der Datensätze zu tun? Oder willst du darauf hinaus, dass _alle_ einen "Stammdatensatz" betreffenden Daten in _eine_ Tabelle gehören, egal ob jedes Datum bei jedem Datensatz vorhanden ist?

        Tschö, Auge

        --
        Die deutschen Interessen werden am Liechtenstein verteidigt.
        Veranstaltungsdatenbank Vdb 0.2
        1. hi,

          Dann hat man doch wieder das Problem, dass die Tabellen zu überladen sind.
          Wieso? Soundsoviele Datensätze, ja und? Dazu ist eine Datenbank da.

          Es ging mir nicht um die Daten selbst, sondern um die Aufteilung der Daten in verschiedene Tabellen.

          Wie steht es da um die Normalisierung?
          Oder willst du darauf hinaus, dass _alle_ einen "Stammdatensatz" betreffenden Daten in _eine_ Tabelle gehören,

          Nein, eben nicht. Normalisierung bedeutet doch, die einzelnen Felder auf verschiedene Tabellen zu verteilen, um eben nicht alle Daten in nur einer Tabelle zu haben.

          Wenn ich beispielsweise neue Felder benötige, weil ich neue Datensätze habe, die ich speichern muss, macht es doch Sinn, neue Tabellen anzulegen, statt die bestehenden Tabellen einfach um ein Paar Felder zu erweitern.

          So hatte ich jedenfalls Vinzenz Antwort verstanden.

          mfg

          1. Hallo

            Wie steht es da um die Normalisierung?
            Oder willst du darauf hinaus, dass _alle_ einen "Stammdatensatz" betreffenden Daten in _eine_ Tabelle gehören,

            Nein, eben nicht. Normalisierung bedeutet doch, die einzelnen Felder auf verschiedene Tabellen zu verteilen, um eben nicht alle Daten in nur einer Tabelle zu haben.

            Normalisierung bedeutet, dass Daten, die in einer 1-zu-1-Beziehung stehen zusammengehören. Das wären z.B. für eine Person der Familienname und das Geburtsdatum. Beim Vornamen könnte man schon wieder überlegen, ob man mehrere Vornamen unbedingt voneinander getrennt speichern will (warum das auch immer der Fall sein sollte). Wenn man von der Möglichkeit von mehreren Vornamen absieht, gibt es jedes dieser Daten für jede Person nur _einmal_, also gehören sie zusammen.

            Daten, die in einer 1-zu-n- oder n-zu-1-Beziehung stehen, gehören in verschiedene Tabellen, die dann miteinander verknüpft werden können. Dazu gehören die Telefonnummern der oben genannten Person, die Kennzeichen der auf ihn angemeldeten Fahrzeuge oder auch mehrere Wohnsitze (Haupt- und Nebenwohnung).

            Diese Daten gehören in verschiedene Tabellen, deren Datensätze über die ID der Person, zu der sie gehören, verknüpft sind.

            Wenn ich beispielsweise neue Felder benötige, weil ich neue Datensätze habe, die ich speichern muss, macht es doch Sinn, neue Tabellen anzulegen, statt die bestehenden Tabellen einfach um ein Paar Felder zu erweitern.

            Wie gesagt, das kommt darauf an, in welcher Beziehung die neuen Daten zu bereits bestehenden Daten stehen.

            Tschö, Auge

            --
            Die deutschen Interessen werden am Liechtenstein verteidigt.
            Veranstaltungsdatenbank Vdb 0.2
            1. hi,

              Wie gesagt, das kommt darauf an, in welcher Beziehung die neuen Daten zu bereits bestehenden Daten stehen.

              Zitat, auf das ich mich eigentlich bezog:

              Ich will keine neue Tabelle anlegen, sobald ich z.B. eine neue Seite im Gesamtgefüge ergänze, sondern nur bei einem neuen _Typ_ von Seite. Quasi ein neues Modul, das irgendwas besonderes kann. Warum ist es eine schlechte Idee, für eine neue Funktionalität auch neue Tabellen in der DB anzulegen? Die unterschiedlichen Module benötigen ja ganz unterschiedliche Daten zum Arbeiten.

              Da sollte eine neue Tabelle doch durchaus berechtigt sein.

              mfg

              1. Hallo

                Wie gesagt, das kommt darauf an, in welcher Beziehung die neuen Daten zu bereits bestehenden Daten stehen.

                Zitat, auf das ich mich eigentlich bezog:

                Ich will keine neue Tabelle anlegen, sobald ich z.B. eine neue Seite im Gesamtgefüge ergänze, sondern nur bei einem neuen _Typ_ von Seite. Quasi ein neues Modul, das irgendwas besonderes kann. Warum ist es eine schlechte Idee, für eine neue Funktionalität auch neue Tabellen in der DB anzulegen? Die unterschiedlichen Module benötigen ja ganz unterschiedliche Daten zum Arbeiten.

                Da sollte eine neue Tabelle doch durchaus berechtigt sein.

                Ja, natürlich, wurde hier ja auch schon mehrfach gesagt. Ein neues "Modul" ist ja (hoffentlich) eigenständig und benutzt im Zweifelsfall bestehende Datenbestände (nur lesend) mit.

                Ein Beispiel wäre eine bestehende Anmeldung auf einer Seite, um z.B. in einem Forum zu posten und die Mitbenutzung dieser Anmeldedaten für ein Uploadskript für angemeldete Benutzer. Das Uploadskript hat für seinen Betrieb eine oder mehrere eigene Datenbanktabellen, in denen es schreiben und lesen kann, wie es lustig ist/programmiert wurde. Die Anmeldedaten (einer anderen Skriptanwendung) werden jedoch von diesem Skript zwar gelesen aber nicht verändert, erweitert etc., also weder datentechnisch noch strukturell. Falls dies doch nötig sein sollte, dann sollte das im Kontext des Anmeldeskripts, sozusagen des "Mutterskripts der DB(-Tabelle)", erfolgen.

                Tschö, Auge

                --
                Die deutschen Interessen werden am Liechtenstein verteidigt.
                Veranstaltungsdatenbank Vdb 0.2
    2. Hallo Vinzenz.

      [...] Diese können dann nämlich davon unabhängig Artikel, Bildergalerie, Kontaktformulare, Kategorien (zum Gruppieren zusammengehöriger Seiten) oder sonstwas sein -- jede mit einer eigenen Funktionsweise und anderen Daten, die für den Betrieb wichtig sind. Für jeden dieser Typen gibt es in der DB also auch einen eigenen Typ von Tabelle,

      Es ist keine gute Idee, für Neues "neue Tabellen" oder auch nur "neue Spalten" anlegen zu wollen.

      Verstehen wir uns richtig? Ich will keine neue Tabelle anlegen, sobald ich z.B. eine neue Seite im Gesamtgefüge ergänze, sondern nur bei einem neuen _Typ_ von Seite. Quasi ein neues Modul, das irgendwas besonderes kann. Warum ist es eine schlechte Idee, für eine neue Funktionalität auch neue Tabellen in der DB anzulegen? Die unterschiedlichen Module benötigen ja ganz unterschiedliche Daten zum Arbeiten. Als Beispiel:

      Ein Seitentyp "Artikel" existiere bereits. Zugehörige Daten in der DB sind meinetwegen Überschrift, Text (der eigentliche Artikel), Veröffentlichungsdatum. Mein CMS kann nun also beliebig viele "Artikel" verwalten, die auch alle als Datensätze in einer Tabelle "articles" gespeichert werden. Nun möchte ich einen neuen Seitentyp "Bildergalerie" mit ganz anderer Funktionalität hinzufügen. Dafür benötige ich beispielsweise eine Tabelle, in der Bildpfade, Bildbeschreibungen usw. gespeichert werden. Die Tabelle "articles" kann das nicht leisten. Als nächstes soll meinetwegen ein Seitentyp "Gästebuch" zur Verfügung stehen. Das Gästebuch benötigt eine Tabelle, in der die Gästebucheinträge mit Datum, Autor, Emailadresse und Beitragstext gespeichert werden. Auch das ist kein "Artikel".

      Viele Grüße von Alex

      1. Hallo

        Hallo Vinzenz.

        [...] Diese können dann nämlich davon unabhängig Artikel, Bildergalerie, Kontaktformulare, Kategorien (zum Gruppieren zusammengehöriger Seiten) oder sonstwas sein -- jede mit einer eigenen Funktionsweise und anderen Daten, die für den Betrieb wichtig sind. Für jeden dieser Typen gibt es in der DB also auch einen eigenen Typ von Tabelle,

        Es ist keine gute Idee, für Neues "neue Tabellen" oder auch nur "neue Spalten" anlegen zu wollen.

        Verstehen wir uns richtig?

        Offensichtlich nicht.

        Ich will keine neue Tabelle anlegen, sobald ich z.B. eine neue Seite im Gesamtgefüge ergänze,

        davon bin ich auch nicht ausgegangen.

        sondern nur bei einem neuen _Typ_ von Seite.

        ja, so habe ich das verstanden. Und ich verstand es so, dass dies ein redaktioneller Benutzer jederzeit tun könnte. Das wäre meiner Meinung nach ungünstig.

        Quasi ein neues Modul, das irgendwas besonderes kann. Warum ist es eine schlechte Idee, für eine neue Funktionalität auch neue Tabellen in der DB anzulegen? Die unterschiedlichen Module benötigen ja ganz unterschiedliche Daten zum Arbeiten.

        Wenn es sich um eigenständige Module handelt, die z.B. installiert und freigeschaltet werden können, dann ist das durchaus ok. So habe ich Dich aber nicht verstanden.

        Als Beispiel:

        Ein Seitentyp "Artikel" existiere bereits. Zugehörige Daten in der DB sind meinetwegen Überschrift, Text (der eigentliche Artikel), Veröffentlichungsdatum. Mein CMS kann nun also beliebig viele "Artikel" verwalten, die auch alle als Datensätze in einer Tabelle "articles" gespeichert werden. Nun möchte ich einen neuen Seitentyp "Bildergalerie" mit ganz anderer Funktionalität hinzufügen. Dafür benötige ich beispielsweise eine Tabelle, in der Bildpfade, Bildbeschreibungen usw. gespeichert werden. Die Tabelle "articles" kann das nicht leisten.

        Ja, ein eigenständiges Modul, das durchaus den generischen "Artikel" als Basisklasse nutzen darf. Selbstverständlich erfordert dies eigenen Code und darf auch spezifische Tabellen verwenden, die durch die Installationsroutine des Moduls erstellt werden. Dies stört die normalen Artikel in keiner Weise, deren Code bleibt unangetastet, die DB-Abfragen ändern sich ebenfalls nicht.

        Als nächstes soll meinetwegen ein Seitentyp "Gästebuch" zur Verfügung stehen. Das Gästebuch benötigt eine Tabelle, in der die Gästebucheinträge mit Datum, Autor, Emailadresse und Beitragstext gespeichert werden. Auch das ist kein "Artikel".

        Das gleiche wie vorher. Das ist doch kein Problem. Halte die Module unabhängig voneinander, bzw. setze bestimmte Module für eine Erweiterung voraus (Abhängigkeitsbaum).

        Was hat dies mit Deiner Ausgangsfragestellung zu tun? Ich zitiere:

        allerdings stört mich etwas daran. An der Stelle, wo die zu einem Knoten gehörige Seite gefunden werden soll, muß ich quasi mit allen vorhandenen Typen von Seitentabellen vergleichen, ob ein Eintrag mit bestimmter Knoten-ID existiert.

        Das verstehe ich in dem von Dir skizzierten Zusammenhang überhaupt nicht. Der Knoten muss selbstverständlich *wissen*, wo seine Daten zu finden sind - und diese nicht ziellos suchen.

        Das wird also ein ziemlich großer JOIN, in dem alle möglichen Tabellen vorkommen -- eben so viele, wie unterschiedliche Seitentypen existieren.

        Nein, natürlich nicht. Der Typ ist im Knoten vermerkt.

        Ich könnte die benötigte Query dynamisch aus allen "bekannten" Tabellennamen zusammensetzen, dann muß ich bei Ergänzungen neuer Seitentypen zumindest nicht die jedesmal von Hand die Query umschreiben. Trotzdem wächst bei solchen Ergänzungen dieses JOIN-Gebilde immer und immer weiter.

        Das ist eben ein falsches Konzept. Bestehendes darf nicht durch ein Erweiterungsmodul verkompliziert werden.

        Freundliche Grüße

        Vinzenz

        1. Hallo Vinzenz.

          Wenn es sich um eigenständige Module handelt, die z.B. installiert und freigeschaltet werden können, dann ist das durchaus ok. So habe ich Dich aber nicht verstanden.

          Genau so war es allerdings gemeint. Ok, da wir nun offensichtlich von der gleichen Sache reden, kommen wir zum Thema. :-)

          Was hat dies mit Deiner Ausgangsfragestellung zu tun? Ich zitiere:

          allerdings stört mich etwas daran. An der Stelle, wo die zu einem Knoten gehörige Seite gefunden werden soll, muß ich quasi mit allen vorhandenen Typen von Seitentabellen vergleichen, ob ein Eintrag mit bestimmter Knoten-ID existiert.

          Das verstehe ich in dem von Dir skizzierten Zusammenhang überhaupt nicht. Der Knoten muss selbstverständlich *wissen*, wo seine Daten zu finden sind - und diese nicht ziellos suchen.

          Genau dort setzte meine Frage an. Wenn das Programm wirklich _nur_ eine Knoten-ID erhält, weiß es nicht, wo die zugehörige Seite zu suchen ist. Eine Möglichkeit wäre wie gesagt das "Durchsuchen" aller Tabellen, die Seitentypen repräsentieren. Da die Knoten-ID nur einmalig vergeben wird, wird sie entweder genau in einer dieser Tabellen gefunden oder gar nicht. Das ist nicht wirklich "ziellos", aber eben sehr aufwendig.

          Das wird also ein ziemlich großer JOIN, in dem alle möglichen Tabellen vorkommen -- eben so viele, wie unterschiedliche Seitentypen existieren.

          Nein, natürlich nicht. Der Typ ist im Knoten vermerkt.

          Das war eine der Umstrukturierungsvorschläge, um die ich eingangs bat. Danke. :-) Du schlägst also vor, den Seitentyp mit im Hierarchiebaum zu speichern. An irgendeiner zentralen Stelle im Programm -- dort sind bei Ergänzungen neuer Seitentypen dann auch Ergänzungen nötig -- muß also vermerkt sein, welcher Typeneintrag in diesem Baum welcher Tabelle entspricht. Hmm, ok. Ist 'ne Möglichkeit. Ich wollte im Hierarchiebaum eigentlich wirklich nur ganz abstrakt "Seiten" abbilden, unabhängig vom speziellen Typ. Aber mit dieser Zusatzinfo ist es einfacher zu handhaben. So werd ich's wohl machen.

          Ich könnte die benötigte Query dynamisch aus allen "bekannten" Tabellennamen zusammensetzen, dann muß ich bei Ergänzungen neuer Seitentypen zumindest nicht die jedesmal von Hand die Query umschreiben. Trotzdem wächst bei solchen Ergänzungen dieses JOIN-Gebilde immer und immer weiter.

          Das ist eben ein falsches Konzept. Bestehendes darf nicht durch ein Erweiterungsmodul verkompliziert werden.

          Meine Rede. Genau deshalb überhaupt dieser Thread, um den bisherigen Ansatz zu diskutieren. ;-)

          Grüße von Alex

        2. Ich nochmal.

          Der Typ ist im Knoten vermerkt.

          Das ursprüngliche Problem mit dem Riesen-JOIN bleibt bei dieser Lösung allerdings bestehen, wenn ich z.B. den kompletten Hierarchiebaum mit Titeln der Seiten für eine Navigation holen möchte.

          Nehmen wir mal an, daß jede Seite selber weiß, wie sie heißt, d.h. sie speichert ihren Titel zusammen mit ihren anderen Daten in der entsprechenden DB-Tabelle. Beim Zusammenstellen des Baums muß dann doch wieder mit jeder Tabelle geJOINed werden, für die ein entsprechender Knoten im Baum vorhanden ist. OOP-mäßig gedacht, kann man natürlich einen abstrakten Basistyp für Seiten schaffen, der auf jeden Fall auch den Seitentitel enthält, der für alle Seiten vorhanden ist. Alle speziellen Seitentypen erben dann von diesem Basistyp. Auf DB-Ebene ist es vermutlich nicht sinnvoll, noch eine weitere Tabelle zu erstellen, die diesen Basistyp abbildet. Vermutlich sollten also eher die gemeinsamen Attribute (z.B. der Seitentitel) mit in die Knotentabelle (Hierarchiebaum) wandern.

          Hmm, ich vermute fast, daß die Knotentabelle auf diesem Weg noch um einige andere Attribute erweitert wird (Erstellungsdatum etc.). Aber irgendwie mißfällt mir daran, daß die Seiten dann z.B. nicht mehr selber wissen, wie sie heißen, sondern für solche Informationen die Knotentabelle konsultieren müssen. Und doppelte Datenhaltung wäre vermutlich eine _noch_ schlechtere Idee -- das fällt schonmal als Lösung weg. Was würdest Du hier empfehlen, Vinzenz?

          Grüße von Alex

          1. Hallo

            Das ursprüngliche Problem mit dem Riesen-JOIN bleibt bei dieser Lösung allerdings bestehen, wenn ich z.B. den kompletten Hierarchiebaum mit Titeln der Seiten für eine Navigation holen möchte.

            wieso? Wie ich bereits schrieb, sollten die Seiten, die von Modulen produziert werden, auf dem Basisobjekt "Artikel" (oder wie auch immer) aufsetzen. Alles, was für die Navigation benötigt wird, muss jedes Objekt vom Typ Artikel mit sich bringen, d.h. diese Daten gehören meiner Meinung nach in die Knotentabelle.

            Die Navigation kann sich doch nicht ändern, nur weil ein neues Modul hinzukommt.

            Freundliche Grüße

            Vinzenz

            1. Hallo Vinzenz.

              Das ursprüngliche Problem mit dem Riesen-JOIN bleibt bei dieser Lösung allerdings bestehen, wenn ich z.B. den kompletten Hierarchiebaum mit Titeln der Seiten für eine Navigation holen möchte.

              wieso? Wie ich bereits schrieb, sollten die Seiten, die von Modulen produziert werden, auf dem Basisobjekt "Artikel" (oder wie auch immer) aufsetzen. Alles, was für die Navigation benötigt wird, muss jedes Objekt vom Typ Artikel mit sich bringen, d.h. diese Daten gehören meiner Meinung nach in die Knotentabelle.

              Ja, der Anfang des vorigen Postings war ja auch nur ein (laut geäußerter) Gedanke dazu wie es aussieht, wenn die Knotentabelle eben (fast) ausschließlich für die Abbildung der Seitenhierarchie zuständig ist. Von dort aus bin ich ja dann auch an dem Punkt angekommen, wo die Knotentabelle eher eine Art Basisklasse für alle Seitentypen als eine reine Strukturabbildung sein sollte. Ich probier erstmal, wie weit ich damit komme ...

              Grüße von Alex

          2. Hi,

            dann machst du einfach dasselbe in PHP was du in der Datenbank machst: Du abstrahierst auf einen allgemeinen Basistypen von "Seite" und schreibst dann dazu weiter abgeleitete Klassen mit speziellen Methoden, dazu entsprechen alle davon noch schön einem gleichen gleichen Interfacetypen. Wird dann eine schöne kleine Welt aus "Factories", welche für den jeweiligen Knotentypen die Daten nur aus den dafür notwendigen Tabellen zusammensuchen indem sie ein spezifisches SQL Statement genau dafür bauen.

            Für eine hierarchische Generierung kannst du z.b. das Visitor-Pattern implementieren.

            Gleiche (eindimensionale) Attribute, die z.b. häufig verwendet werden, würde ich als "payload" in der Knotentabelle mitverwalten (Knotentyp, Ersteller, Datum ...).

            Oder du nimmst einfach schon ein existierendes CMS? ;)

            Ciao, Frank