ichselbst: Frage zum Design einer mySQL-Tabelle...

Hallo!

Mal eine Frage an alle mySQL-Kenner hier bzgl. des "Designs" einer Tabelle. Ich habe eine Seite, auf der ich momentan etwa 20.000 registriete Benutzer habe. Jeder Benutzer hat eine "Inbox", in der er Nachrichten von anderen Benutzern empfangen kann. Bisher habe ich das alles mit Flatfiles (also einfachen Textdateien) gemacht. Die Nachrichten wurden also als einfache Textzeile (empfaenger, absender, text) abgespeichert und für jeden Benutzer existiert eine Textdatei.

Da ext2 ab ca. 20000 Dateien pro Verzeichnis beginnt, ziemlich langsam zu werden, muss ich das ganze jetzt wohl oder übel auf eine Datenbank umstellen.

Die Frage ist: Wie speichere ist das am besten und efizientesten in einer Datenbank? Eine große 3-spaltige Tabelle, in die ich alle Nachrichten aller Benutzer reinschreibe (empfaengername, absender, text)? Die Nachrichten eines bestimmten Benutzers müsste ich dann bei jedem Zugriff über "SELECT text, absender WHERE empfaenger=einuser" raussuchen. Ist das halbwegs effizient oder gibt es eine bessere Möglichkeit?

Danke schon mal für eure Meinungen...

Grüße
ichselbst

  1. Hello,

    Die Frage ist: Wie speichere ist das am besten und efizientesten in einer Datenbank? Eine große 3-spaltige Tabelle, in die ich alle Nachrichten aller Benutzer reinschreibe (empfaengername, absender, text)? Die Nachrichten eines bestimmten Benutzers müsste ich dann bei jedem Zugriff über "SELECT text, absender WHERE empfaenger=einuser" raussuchen. Ist das halbwegs effizient oder gibt es eine bessere Möglichkeit?

    Man sollte den Namen des Empfängers vom OWNER des Datensatzes trennen. Gibt es denn vielleicht auch eine Dialog-Funktion, mit der festestellt wird, welche Kommunikation zwei Teilnehmer untereinander betrieben haben?

    ID_msg      bigint unsigned primary  ID der Message
      ID_OWNER    bigint unsigned
      ID_SENDER   bigint unsigned
      MSG_DATE    datetime
      MSG_SUBJ    char(40)
      MSG_TEXT    text                     Text der Meldung
      MSG_READ    tiny int                 Die Meldung ist schon geöffnet worden
      MSG_REPLY   tiny int                 Die Meldung wurde schon bearbeitet
      MSG_DEL     tiny int                 Delete-Flag um nicht bei jeder Löschung tatsächlich
                                           löschen zu müssen. Da stirbt die Performance
      MSG_OP_FLAG tiny int                 Merker für den Operator, wenn Meldungen z.B. ausgeblendet
                                           werden müssen aber nicht gelöscht werden dürfen

    Das gibt geschäftze ca. 1.300 Bytes pro Datensatz
      Das macht bei 100 Meldungen pro User, und 20.000 Usern ca. 2.6 GB

    Damit ist MySQL 3.x für Deinen Anwendungsfall ungeeignet. Die Spezifikation von
      4.x kenn ich noch nicht auswendig.

    Da wirst Du wohl entweder ein intelligenteres Flat-File Komzept bauen müssen, oder gleich auf z.B. Informix gehen müssen. Denn bei einem DBMS gleich in die Begrenzug zu fahen, ist ja nicht sehr sinnvoll.

    Harzliche Grüße aus http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau
    1. Hallo Tom!

      Man sollte den Namen des Empfängers vom OWNER des Datensatzes trennen.

      Das hab ich nicht ganz verstanden... Der Empfängername ist in meinem Fall immer der "usernick" des Empfängers [a-zA-Z0-9_], den ich als "global key" benutze.

      Gibt es denn vielleicht auch eine Dialog-Funktion, mit der festestellt wird, welche Kommunikation zwei Teilnehmer untereinander betrieben haben?

      Ja. In meinem "Flatfile-System" mache ich das so, dass ich alle Nachrichten, die ein Benutzer schreibt oder empfängt, in "seine" .txt-Datei schreibe, inklusive Unix-Timestamp. Beim Auslesen brauche ich dann nur den Nickname des Kommunikationspartners zu "greppen" und die Zeilen nach dem Timestamp zu sortieren. Damit hab ich dann den kompletten Dialog zweier Teilnehmer chronologisch geordnet.

      ID_msg      bigint unsigned primary  ID der Message

      So eine ID brauch ich bei SQL wohl tatsächlich. In meinen Flatfiles benutze ich als msg-ID einfach den Timestamp, da es eher unwahrscheinlich ist, dass ein Nutzer 2 Nachrichten in der gleichen Sekunde bekommt.

      ID_OWNER    bigint unsigned
        ID_SENDER   bigint unsigned

      Das wären eher varchar(20)...

      MSG_DATE    datetime

      Mit Unix-Timestamps kann mySQL nicht umgehen, oder?

      MSG_SUBJ    char(40)

      Gibt es nicht, kann also weggelassen werden.

      MSG_TEXT    text        Text der Meldung
        MSG_READ    tiny int    Die Meldung ist schon geöffnet worden
        MSG_REPLY   tiny int    Die Meldung wurde schon bearbeitet
        MSG_DEL     tiny int    Delete-Flag um nicht bei jeder Löschung tatsächlich
                                löschen zu müssen. Da stirbt die Performance
        MSG_OP_FLAG tiny int    Merker für den Operator, wenn Meldungen z.B. ausgeblendet
                                werden müssen aber nicht gelöscht werden dürfen

      Die Flags sind natürlch wirklich eine gute Idee. Die hab ich bisher nicht benutzt, hört sich aber extrem sinnvoll an. Vor allem Danke für den Tipp, dass dauerndes löschen einzelner Einträge die Performance beeinträchtigt!

      Das gibt geschäftze ca. 1.300 Bytes pro Datensatz
      Das macht bei 100 Meldungen pro User, und 20.000 Usern ca. 2.6 GB
      Damit ist MySQL 3.x für Deinen Anwendungsfall ungeeignet. Die Spezifikation von 4.x kenn ich noch nicht auswendig.

      Siehe http://dev.mysql.com/doc/mysql/en/Table_size.html
      Sechster Kommentar von oben. Max size auf ext2 ist 2 TB.

      Da wirst Du wohl entweder ein intelligenteres Flat-File Komzept bauen müssen, oder gleich auf z.B. Informix gehen müssen. Denn bei einem DBMS gleich in die Begrenzug zu fahen, ist ja nicht sehr sinnvoll.

      Mein bisheriges Flatfile-System hat auch recht gut funktioniert. Nur müsste ich jetzt die User in Gruppen aufteilen und die Datenfiles dann in verschiedene Unterverzeichnisse. Warum werden denn DBMS dann so oft benutzt, statt einfach Flatfiles zu nehmen? Also, was in denn dann der große Vorteil von DBMS? Sorry, vielleicht ein blöde Frage, aber ich hab bisher immer nur Flatfiles benutzt und hatte nie große Probleme damit. Andererseits sieht man auch immer wieder, dass Leute für 20 Gästebucheinträge eine DBMS bemühen...

      Danke für deine Hilfe und Viele Grüße!
      ichselbst

      1. Hello M. (bist Du's?),

        Man sollte den Namen des Empfängers vom OWNER des Datensatzes trennen.

        Das hab ich nicht ganz verstanden... Der Empfängername ist in meinem Fall immer der "usernick" des Empfängers [a-zA-Z0-9_], den ich als "global key" benutze.

        kommt immer darauf an, wieviele Daten noch dranhängen und pb die ID nicht weniger Speicher kostet und ob der UserNick wirklich eineindeutig ist.

        Gibt es denn vielleicht auch eine Dialog-Funktion, mit der festestellt wird, welche Kommunikation zwei Teilnehmer untereinander betrieben haben?

        Ja. In meinem "Flatfile-System" mache ich das so, dass ich alle Nachrichten, die ein Benutzer schreibt oder empfängt, in "seine" .txt-Datei schreibe, inklusive Unix-Timestamp. Beim Auslesen brauche ich dann nur den Nickname des Kommunikationspartners zu "greppen" und die Zeilen nach dem Timestamp zu sortieren. Damit hab ich dann den kompletten Dialog zweier Teilnehmer chronologisch geordnet.

        Ganz schön schlau, dafür die Unix-Funktionen zu benutzen. Die sind nämlich extrem schnell.

        ID_msg      bigint unsigned primary  ID der Message

        So eine ID brauch ich bei SQL wohl tatsächlich. In meinen Flatfiles benutze ich als msg-ID einfach den Timestamp, da es eher unwahrscheinlich ist, dass ein Nutzer 2 Nachrichten in der gleichen Sekunde bekommt.

        Es ist besser, wenn man dedizierte Ändrungen (Löschen, Update) vornehmen will.

        ID_OWNER    bigint unsigned
          ID_SENDER   bigint unsigned

        Das wären eher varchar(20)...    ## bigint wäre dann nur 8Bytes lang, allerdings
                                          ## nenötigt man dann für die Abfage einen Join

        MSG_DATE    datetime

        Mit Unix-Timestamps kann mySQL nicht umgehen, oder?

        Doch, aber sie könnten bei 150 "gleichzeitigen" Prozessen nicht granular genug sein. Außerdem speichert MySQL die Timnestamps auch im Datetime-Format, was einen größeren Definitionsbereich bedeutet.

        MSG_SUBJ    char(40)

        Gibt es nicht, kann also weggelassen werden. ## auf die 40 Bytes kommt es dann auch nicht mehr an

        MSG_TEXT    text        Text der Meldung
          MSG_READ    tiny int    Die Meldung ist schon geöffnet worden
          MSG_REPLY   tiny int    Die Meldung wurde schon bearbeitet
          MSG_DEL     tiny int    Delete-Flag um nicht bei jeder Löschung tatsächlich
                                  löschen zu müssen. Da stirbt die Performance
          MSG_OP_FLAG tiny int    Merker für den Operator, wenn Meldungen z.B. ausgeblendet
                                  werden müssen aber nicht gelöscht werden dürfen

        Die Flags sind natürlch wirklich eine gute Idee. Die hab ich bisher nicht benutzt, hört sich aber extrem sinnvoll an. Vor allem Danke für den Tipp, dass dauerndes löschen einzelner Einträge die Performance beeinträchtigt!

        Das gibt geschäftze ca. 1.300 Bytes pro Datensatz
        Das macht bei 100 Meldungen pro User, und 20.000 Usern ca. 2.6 GB
        Damit ist MySQL 3.x für Deinen Anwendungsfall ungeeignet. Die Spezifikation von 4.x kenn ich noch nicht auswendig.

        Siehe http://dev.mysql.com/doc/mysql/en/Table_size.html
        Sechster Kommentar von oben. Max size auf ext2 ist 2 TB.

        Gut zu wissen...

        Da wirst Du wohl entweder ein intelligenteres Flat-File Komzept bauen müssen, oder gleich auf z.B. Informix gehen müssen. Denn bei einem DBMS gleich in die Begrenzug zu fahren, ist ja nicht sehr sinnvoll.

        Mein bisheriges Flatfile-System hat auch recht gut funktioniert. Nur müsste ich jetzt die User in Gruppen aufteilen und die Datenfiles dann in verschiedene Unterverzeichnisse. Warum werden denn DBMS dann so oft benutzt, statt einfach Flatfiles zu nehmen? Also, was in denn dann der große Vorteil von DBMS? Sorry, vielleicht ein blöde Frage, aber ich hab bisher immer nur Flatfiles benutzt und hatte nie große Probleme damit. Andererseits sieht man auch immer wieder, dass Leute für 20 Gästebucheinträge eine DBMS bemühen...

        Kann man sich lange mit auseinandersetzen. Dennis Riehle und ich stricken da immer noch an einem Artikel, der garantiert 50 Seiten bekommen wird. http://forum.de.selfhtml.org/archiv/2004/5/82138/

        Die erste Möglichkeite hat schon 119 Seiten Thread verursacht.

        Harzliche Grüße aus http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau
        1. Hello M. (bist Du's?),

          Hallo Tom! ...nein, "M" bin ich nicht, eher "C" ;)

          kommt immer darauf an, wieviele Daten noch dranhängen und pb die ID nicht weniger Speicher kostet und ob der UserNick wirklich eineindeutig ist.

          Ok, jetz hab ich verstanden, was du meintest...

          Ganz schön schlau, dafür die Unix-Funktionen zu benutzen. Die sind nämlich extrem schnell.

          Das ganze ist in Perl geschrieben, da bietet sich grep und sort an... Trotzdem schön zu hören, dass es "schlau" ist! *g*

          MSG_SUBJ    char(40)
          Gibt es nicht, kann also weggelassen werden. ## auf die 40 Bytes kommt es dann auch nicht mehr an

          Stimmt...

          Kann man sich lange mit auseinandersetzen. Dennis Riehle und ich stricken da immer noch an einem Artikel, der garantiert 50 Seiten bekommen wird. Die erste Möglichkeite hat schon 119 Seiten Thread verursacht.

          Habs gerade mal überflogen. Also sind Flatfiles doch nicht unbedingt so "böse" wie ich immer gehört habe... Ich denke, ich werd erstmal auf den mySQL-Umbau verzichten, und das ganze über Flatfiles machen. Dann brauch ich nur ein paar Funktionen umzuschreiben, über die alle Zugriffe auf die Datendateien gemacht werden. Über das Indexfile kann ich dann die Benutzer den verschiedenen Unterverzeichnissen zuordnen... mal sehn, ob ich das zum Laufen bekomme so dass ich letztlich 100.000 User oder so da drin haben kann, ohne Probleme zu bekommen...

          Danke für deine Tipps, die haben mir sehr geholfen!

          Christian
          www.elligue.com

          1. Habs gerade mal überflogen. Also sind Flatfiles doch nicht unbedingt so "böse" wie ich immer gehört habe...

            flatfiles sind nicht böse, weil sie nicht funktionieren, sondern weil man damit keine datenunabhängigkeit hat.

            Ilja

            1. Hi!

              Habs gerade mal überflogen. Also sind Flatfiles doch nicht unbedingt so "böse" wie ich immer gehört habe...

              flatfiles sind nicht böse, weil sie nicht funktionieren, sondern weil man damit keine datenunabhängigkeit hat.

              Und das bedeutet?

              Gruß
              ichselbst

              1. yo,

                Und das bedeutet?

                dass man direkt auf die daten zugreift und somit jedes andere programm, dass diese daten nutzen will, sich den strukturen anpassen oder man die struktur ändern muss. privat ist das nicht immer so ein schlagendes argument, für firmen hat sich das aber als zu unflexibel und zu teuer dargestellt.

                Ilja

                1. Moin!

                  dass man direkt auf die daten zugreift und somit jedes andere programm, dass diese daten nutzen will, sich den strukturen anpassen oder man die struktur ändern muss. privat ist das nicht immer so ein schlagendes argument, für firmen hat sich das aber als zu unflexibel und zu teuer dargestellt.

                  Ach so. Da geb ich dir Recht. Bei größeren Strukturen ist es wohl durchaus wichtig, immer gleiche Formate (Standards) zu haben. Für mich ist in erster Linie "Performance" wichtig, da mein lieber kleiner Puretec-Server nur schlappe 256 MB an RAM zur Verfügung hat und ich neben dieser auch noch ein paar andere Seiten da drauf hab. Naja, der Aufwandt der Umbauarbeit, die nötig wäre um das ganze auf mySQL umzustellen, ist wohl auch noch ein Grund... ;)

                  Falls es interessiert: Ich hab jetzt die "Userdatenbank" (wenn auch bisher nur auf dem Testsystem) so gebaut, dass jeder Nutzer in in einem Unterverzeichnis liegt, dessen Name einfach der erste Buchstabe des Benutzernamen ist (also 37 Unterverzeichnisse [a-z0-9_]). Scheint gut zu klappen, nu sind es nur noch maximal 2000 Dateien pro Verzeichnis, hab also noch eine Menge Luft nach oben.

                  Danke nochmal für die nützlichen Infos die ich hier bekommen habe!
                  ichselbst

                  1. Hello,

                    man muss eben alle wichtigen Strategien slebst implementieren und irgendwann hat man die Funktionalität der Datenbank nachgebaut. Schließlich arbeitet eine Datenbank auch nur irgendwie auf Flatfiles *gg*

                    Du musst da sleber die Berechnungen machen, die Dir sagen, ob ein eigenes DBMS (Flatfiles) oder eine Datenbank das richtige ist. Da MySQL zur Zeit nichts extra kostet, wäre dieses DBMS also passend. Die nächste Stufe wäre dann  Informix auf Linux. das kostet auch nur ca. 250E und ist ein Riesensprung in Performance und Professionalität. Oder man versucht es noch mal mit PostGreSQL, das ist wohl auch noch kostenlos.

                    Harzliche Grüße aus http://www.annerschbarrich.de

                    Tom

                    --
                    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                    Nur selber lernen macht schlau
  2. Hallo.

    Die Frage ist: Wie speichere ist das am besten und efizientesten in einer Datenbank?

    Ich würde es wenigstens in zwei Tabellen aufteilen: eine Tabelle 'Benutzer' (id, Benutzerdaten) und eine Tabelle 'Nachrichten' (id des Absenders, id des Empfängers, Nachricht).

    Freundschaft!
    Siechfred

    --
    Punk's not dead: http://www.siechfreds-welt.de/badreligion.shtml
    Dankbarkeit, man spürt sie ja so selten bei den Menschen, und gerade die Dankbarsten finden nicht den Ausdruck dafür, sie schweigen verwirrt, sie schämen sich und tun manchmal stockig, um ihr Gefühl zu verbergen. (Stefan Zweig)
    1. Hallo Siechfred!

      Ich würde es wenigstens in zwei Tabellen aufteilen: eine Tabelle 'Benutzer' (id, Benutzerdaten) und eine Tabelle 'Nachrichten' (id des Absenders, id des Empfängers, Nachricht).

      Schon klar. Die Daten jedes Benutzers liegen natürlich in einer anderen Tabelle.

      Danke dir!
      ichselbst

  3. Cheers!

    Da ext2 ab ca. 20000 Dateien pro Verzeichnis beginnt, ziemlich langsam zu werden, muss ich das ganze jetzt wohl oder übel auf eine Datenbank umstellen.

    Warum kommst Du nicht einfach mit mehreren Verzeichnissen, z.B. einem fuer Nutzer, deren Namen mit A beginnt, u.s.w.?

    Die Frage ist: Wie speichere ist das am besten und efizientesten in einer Datenbank? Eine große 3-spaltige Tabelle, in die ich alle Nachrichten aller Benutzer reinschreibe (empfaengername, absender, text)? Die Nachrichten eines bestimmten Benutzers müsste ich dann bei jedem Zugriff über "SELECT text, absender WHERE empfaenger=einuser" raussuchen. Ist das halbwegs effizient oder gibt es eine bessere Möglichkeit?

    Die allerschlechteste Variante, die auch bereits an den Begrenzungen Deines RDBMS scheitern duerfte, waere die "fuer jeden Nutzer eine Tabelle"-Variante. Es scheint ueberfluessig das hier zu schreiben, aber auf Dateiebene hast Du ja genau das bereits ganz trocken umgesetzt.

    Eine weitere schlechte Variante besteht in der von Dir skizzierten Eintabellenloesung. Weniger wegen der von Dir vermuteteten Performanceeinbruechen, sondern aus Gruenden der Handhabbarkeit der Daten. (ein kleines Beispiel: ein Nutzer, z.b. 'Lude' moechte seinen Namen aendern, was zu einer Datenaenderung an vielleicht 2000 Stellen fuehrt. Zudem sind die Briefpartner ueberrascht, dass sie auf einmal Post im Briefkasten haben von Jemandem, den sie scheinbar gar nicht kennen.)

    Es geht also darum die Entitaeten zu identifizieren und diesen jeweils eine Tabelle zu spendieren. Wen oder was haben wir also da? 1.) den Nutzer 2.) die Nachricht (3.)die Sitzung 4.)das Rechtelevel 5.)den Briefkasten(falls mehr als einer reinschauen duerfen soll)...)

    Diese Tabellen sind dann noch moeglichst naturgetrue zu verknuepfen (wie auch bereits von einigen Forumsteilnehmern skizziert) und das Rundumhappypaket steht bereit.

    Gruss,
    Lude

    --
    "ALDI-Bier ist guut."
    1. Moin!

      Warum kommst Du nicht einfach mit mehreren Verzeichnissen, z.B. einem fuer Nutzer, deren Namen mit A beginnt, u.s.w.?

      Ja, das hab ich letztlich dann auch gemacht. Das was auch am einfachsten zu realisieren, da ich nur ein paar Funktionen (die, die für den Datenzugriff zuständig sind) ändern mußte. Nu hab ich das ganze auf 37 Unterverzeichnisse verteilt [a-z0-9_] und hab Platz für bis zu 100,000 Nutzer.

      Die allerschlechteste Variante, die auch bereits an den Begrenzungen Deines RDBMS scheitern duerfte, waere die "fuer jeden Nutzer eine Tabelle"-Variante. Es scheint ueberfluessig das hier zu schreiben, aber auf Dateiebene hast Du ja genau das bereits ganz trocken umgesetzt.

      *g* Klappt aber recht gut. Auch die Daten jedes Benutzers, liegen jeweils in einer separaten Datei. Der einzige Nachteil ist halt der Overhead, wenn ich ganz viele 1-KB-Dateien habe, aber die Serverplatte hat eh noch so viel frei, ist also nich so tragisch...

      Eine weitere schlechte Variante besteht in der von Dir skizzierten Eintabellenloesung. Weniger wegen der von Dir vermuteteten Performanceeinbruechen, sondern aus Gruenden der Handhabbarkeit der Daten. (ein kleines Beispiel: ein Nutzer, z.b. 'Lude' moechte seinen Namen aendern, was zu einer Datenaenderung an vielleicht 2000 Stellen fuehrt. Zudem sind die Briefpartner ueberrascht, dass sie auf einmal Post im Briefkasten haben von Jemandem, den sie scheinbar gar nicht kennen.)

      Ack! Der Nutzername ist bei mir sozusagen der global key. Der kann also nicht geändert werden, da ich ja sonst durch sämtliche Message-Dateien greppen müßte und s/old/new/g... das würde dauern...

      ... und das Rundumhappypaket steht bereit.

      ;)

      Gruß
      ichselbst