Tabellenstruktur/Forum [PHP/mySQL]

Tobias Menzel

Erfahrenes Mitglied
Hallo,

Ich hoffe, die richtige Kategorie erwischt zu haben.

Im Moment versuche ich mich an einer Art "Mini-Board" mit Flash-FrontEnd und PHP/MySQL hinten; hauptsächlich um mich endlich mal mit Datenbanken zu beschäftigen. ;)

Als Tabellenstruktur habe ich mir in etwa folgendes überlegt:
Code:
Forum:   [ ID ] [ Titel ] [ Datum ] [ ... ]

Thread:  [ ID ] [ Forum_ID ] [ Titel ] [ Geschlossen ] [ Sticky ] [ ... ]

Posting: [ ID ] [ Thread_ID] [ Titel ] [ User_ID] [ Inhalt ] [ ... ]

Und natürlich eine User-Tabelle...

Nun möchte ich z.B. in der Forenansicht für jedes Board die Anzahl Threads und die Anzahl Beiträge anzeigen (zusätzlich den Titel des zuletzt bearbeiteten Threads), die Datenbank aber so weit es geht normalisieren.

Mit der Forensuche habe ich lediglich einen Vorschlag gefunden, auch die Anzahl Postings und die ID des letzten Beitrages als Felder in der Tabelle Threads zu speichern. Das wäre sicher einfacher zu programmieren, aber leider redundant.

Andererseits müsste ich mit meiner Struktur zunächst alle Threads für ein Forum abfragen und dann für jeden Thread die Anzahl Beiträge, und die Summe berechnen, um z.B. die Anzahl Postings pro Forum anzeigen zu lassen - was mit meinen (noch kaum vorhandenen Kentnissen) jede Menge Abfragen bedeuten würde.

Nun meine Frage: Gibt es eine performante Methode/Abfrage, die mir die benötigten Informationen liefert, oder sollte man eine gewisse Redundanz inkauf nehmen?

Gruß
.
 
Hallo!

Eine möglichkeit wäre es beispielsweise, den letzten Beitrag eines Forums dynamisch über eine Abfrage herauszufinden. Wenn das Datenaufkommen nicht allzugroß wird, würde ich diese Möglichkeit wählen. Die eine zusätzliche Abfrage merkt man nicht so schnell ;-)
Sollte das Datenvolumen jedoch groß werden wäre vielleicht eine Art "Zustandstabelle" sinnvoll. Dort trägst du einfach für jedes Forum einen Satz ein und merkst dir den aktuellen "Forumszustand" (-> Letzter Post, Bewertung..etc) in dieser Tabelle...

Gruß Tom
 
Hi,

danke erstmal für die Anregung. Der letzte Beitrag lässt sich sicher recht einfach abfragen. (im Moment habe ich dafür sogar noch ein Feld in der Threads-Tabelle, kommt aber noch raus). Das größere Problem habe ich mit der Anzahl Beiträge/Forum. Gibt es eine Abfrage, mit der ich "in einem Rutsch" die Anzahl Beiträge aller Threads mit einer bestimmten Forum-ID bekomme? Im Moment würde ich alle Threads mit der Forum-ID selektieren und für jeden Thread in dem Ergebnis die Anzahl Beiträge, womit ich pro Forum so viele Abfragen wie Threads hätte (ich muss mich erst noch mit dev.mysql.com anfreunden; sehr übersichtlich finde ich die Seite nicht. ;) ).

Die Idee mit der Zustandstabelle ist nicht schlecht; damit werde ich mich mal befassen, obwohl ich eigentlich die Anzahl Tabellen möglichst gering halten möchte. Hinzu kommt, dass ich die Abfragen über eine Klasse in Flash steuere, die auf ein PHP-Script zugreift, welches das Ergebnis als XML-Objekt zurück gibt - dadurch lege ich mir im Moment aber noch einige Beschränkungen auf.

Ich hatte mir auch schon überlegt, auf eine Tabelle für die Threads ganz zu verzichten... was allerdings wieder zu Redundanzen in der Posting-Tabelle führen würde.

Gruß
.
 
Hallo!

Ich muss mich erst noch mit dev.mysql.com anfreunden; sehr übersichtlich finde ich die Seite nicht. ).

Wenn man mal die Seite zu der durchsuchbaren Hilfe gefunden hat ist alles andere nur noch ein Klacks :)
http://dev.mysql.com/doc/mysql/en/index.html

Das größere Problem habe ich mit der Anzahl Beiträge/Forum. Gibt es eine Abfrage, mit der ich "in einem Rutsch" die Anzahl Beiträge aller Threads mit einer bestimmten Forum-ID bekomme?
Na klar ;-)
Anzahl aller Beiträge für Forum 1 Zählen:
select count(forum_id) from postings where forum_id = 1;

Anzahl aller Beiträe für einen Bestimmten Thread in einem Bestimmten Forum:
select count(thread_id) from postings where forum_id = 1 and thread_id = 1;

Gruß Tom
 
Also Du möchtest eine Tabelle mit folgenden Spalten darstellen?

Titel des Forum
Anzahl Threads im Forum
Anzahl Posts im Forum
Titel des letzten Post
Titel des Threads in dem der Letzte Post war
Autor des letzten Post

Dazu die IDs, um ggf. Links zu setzen?

Dann habe ich mal ein Beispiel.
ABER ACHTUNG: Es ist ungetestet und mit COUNT(DISTINCT... habe ich selbst vorher noch nicht gearbeitet.
Laut MySQL-Manual sollte das aber zumindest in die richtige Richtung gehen.
Ich würde mich über die Fehlermeldung freuen :D
Wenn Fehler auftreten und wir noch mal schauen sollen, dann gib' uns bitte einen DB-Dump der Tabellen mit ein paar Beispieldaten. Ich habe nämlich keine Lust, die Tabelle nachzubauen.

Code:
SELECT 

#Auswahl der jeweiligen Spalten
#Mit Aliasnamen, da sich
#Titel und ID in den Tabellen
#überschneiden.
Forum.ID AS ForumID,
Forum.Titel AS ForumTitel,
Thread.ID AS ThreadID,
Thread.Titel AS ThreadTitel,
Posting.ID AS PostingID,
Posting.Titel AS PostingTitel,
Posting.Datum AS PostingDatum,
User.ID AS AutorID,
User.Name AS AutorName,

#Zähle alle Zeilen mit unterschiedlicher 
#PostingID in der Gruppierung
COUNT(DISTINCT Posting.ID) AS AnzahlPostings,

#Zähle alle Zeilen mit unterschiedlicher 
#ThreadID in der Gruppierung
COUNT(DISTINCT Thread.ID) AS AnzahlThreads,

#Als Basis dient die Tabelle Forum
FROM Forum 

#Kreuzprodukt mit Tabelle Thread unter beachtung
#des Kriteriums hinter ON
LEFT JOIN Thread ON (Thread.Forum_ID=Forum.ID)

#Das gleiche zwischen Thread und Posting
LEFT JOIN Posting ON (Posting.Thread_ID=Thread.ID)

#Und noch mal zwischen Posting und User
LEFT JOIN User ON (Posting.User_ID=User.ID)

#Gruppiere nach der Forums-ID, da
#für jedes Forum nur eine Zeile dargetellt
#werden soll
GROUP BY Forum.ID

#Sortierung nach dem Posting-Datum
#Bei GROUP BY wird ja nur eine Zeile
#aus Posting pro Forum übernommen.
#Ich meine, dass es von der Sortierung
#abhängt, welche das ist.
#Also evtl. mit DESC die Sortierung umkehren.
ORDER BY Posting.Datum #evtl. DESC

#Du könntest vor Posting.Datum natürlich noch
#nach Forum.ID oder Forum.Name sortieren.
#Die Sortierung nach Posting ist nur innerhalb 
#eines Forums releavant.

Eine Zustandstabelle wird vermutlich die Normalisierung verletzen.
Evtl. nicht mal von den exakten Definitionen, da sich Abhängigkeiten über mehrere Tabellen ergeben, aber zumindest normativ, da es ja bei der Normalisierung um Redundanzfreiheit und Datenintegrität geht.
Ich wüsste zumindest keinen Weg, so eine Tabelle einzuführen, ohne dort Daten zu speichern, die sich aus den anderen Tabellen nicht ermitteln lassen.

Gruß hpvw

PS: Ich finde das Manual von dev.mysql.com auch ziemlich fürn A...., vor allem der deutschen Variante fehlen noch viele Dinge aus der englischen. Eine saubere Funktionsreferenz wie auf php.net würde denen gut tun.
Aber es gibt ja auch noch die Seite von Guido Stepken. Außerdem hat vor ein paar Monaten einer hier Forum seine selbstgeschriebene Mysql-Ultra-Kurzreferenz (eine HTML-Seite) einem Beitrag angehängt. Die ist perfekt zum Nachschlagen, wenn man, wie ich, ein Gedächnis wie ein Sieb hat.

EDIT:
Datic hat gesagt.:
obwohl ich eigentlich die Anzahl Tabellen möglichst gering halten möchte.
In der Regel haben normalisierte Datenbanken eher mehr als weniger Tabellen. Nur mit der Zustandstabelle trifft das vermutlich nicht zu.
 
Zuletzt bearbeitet:
@Thomas: die Referenz meinte ich natürlich. Zu finden sind die Dinge schon, ich muss mich allerdings erst in die Syntax einlesen.

select count(thread_id) from postings where forum_id = 1 and thread_id = 1;
, das erfordert aber auch eine forum_id in der Posting-Tabelle, oder irre ich mich hier?

@hpvw: Danke für Deinen Ansatz; da muss ich mich aber gaaanz langsam herantasten, da ich gestern zum ersten Mal einen Blick auf die mySQL-Syntax geworfen habe. ;) Von der Logik her kann ich den Ansatz nachvollziehen - ich muss nur schauen, dass ich das so in meine XML-Struktur eingebaut bekomme, dass ich keine weiteren Spezialklassen brauche. Wenn ich in dieser Richtung weiterkomme, melde ich mich.

@dev.mysql.com: Bin in etwa der selben Meinung; gestern habe ich z.B. vergeblich nach "COUNT" gesucht... muss aber zugeben, das Ding nicht in Ruhe durchgelesen zu haben (was ich wohl hätte tun sollen), sondern einfach fix Ergebnisse haben wollte.

Gruß

EDIT: Ich muss nun erstmal los, werde aber nachher beide Ansätze ausprobieren (Statustabelle und den Vorschlag von hpvw) und die Ergebnisse posten.
.
 
Zuletzt bearbeitet:
Stimmt, und das werde ich wahrscheinlich auch machen, obwohl es schon ein bisschen redundant ist (ist immerhin ein Anfängerprojekt und ich predige selbst immer, mit kleinen Schritten zu beginnen). ;)

Danke an beide für die Tipps, damit komme ich sicher weiter!

Gruß
.
 
@Thomas: Der Link zu Deinem Statement könnte jetzt in eine sehr hitzige Debatte ausarten. :)
Das will ich jetzt zwar gar nicht, aber ganz ohne Kommentar komme ich nicht von diesem Thread weg. :D
Wenn die Datenbank groß genug ist, dass joins dementsprechend "teuer" werden, ist die Normalisierung um so wichtiger, um die Datenkonsistenz zu gewährleisten. Ich bin zwar kein hauptberuflicher DB-Admin, hatte aber schon Einblick in das ein oder andere System. Und um die besonders großen performant und redundanzfrei zu halten gab es oft eine "Arbeitsdatenbank" und eine "Hintergrunddatenbank". Letztere war bis ins Letzte normalisiert und wurde regelmäßig mit der nicht normalen Arbeitsdatenbank abgeglichen. (An der Stelle muss dann sehr sauber gearbeitet werden.)
Christian spricht von kryptisch (ich setze das mal mit unübersichtlich gleich). Das kann, finde ich, im Gegensatz zur Performanz kein Argument sein.
Ich habe auch schon viele (mich eingeschlossen) heulen gesehen, wenn es darum ging, eine nicht normalisierte DB um das ein oder andere Attribut zu erweitern.

Stop, meine Finger tippen und tippen, aber das soll an dieser Stelle genügen.

Gruß hpvw
 
Hallo!

Ich habe ja nicht gesagt,dass man überhaupt nicht Normalisieren soll.:)
Wenn die Datenbank groß genug ist, dass joins dementsprechend "teuer" werden, ist die Normalisierung um so wichtiger, um die Datenkonsistenz zu gewährleisten
Klar, muss die Konsistenz bei einer Datenbank immer gewahrt bleiben und ein "ausreichend" Normalisiertes Datenmodell kann dabei sehr behilflich sein. Jedoch kein bei wirklich großen Datenbanken (mehre GB) eine zu starke Normalisierung Performance Probleme erzeugen. Man könnte hier zwar mit Datenbankmitteln (Z.bsp. Partitionierungen wie z.Bsp. unter Oracle möglich) arbeiten aber die sind dann Datenbankspezifisch. Wenn das etwaige Produkt jedoch extrem Datenbanklastig und dabei gleichzeitig noch Datenbankunabhänig sein soll, dann hat man mit Datenbankspezifischen Optimierungen schon so seine Probleme...

Weiterhin werden die Statements die die Anwendungsentwickler Formulieren müssen dadurch u.U. komplizierter und schwerer zu warten.

Ich bin zwar kein hauptberuflicher DB-Admin, hatte aber schon Einblick in das ein oder andere System. Und um die besonders großen performant und redundanzfrei zu halten gab es oft eine "Arbeitsdatenbank" und eine "Hintergrunddatenbank". Letztere war bis ins Letzte normalisiert und wurde regelmäßig mit der nicht normalen Arbeitsdatenbank abgeglichen. (An der Stelle muss dann sehr sauber gearbeitet werden.)
Ich *dürfte* mich auch schon mit dem ein oder anderen System "amüsieren" (jeweils mit einer mehere GB großen Datenbank)... diese waren dann in der Regel alles andere als Normalsiert und wie du schon angemerkt hast schwer zu erweitern aber immerhin waren sie sehr schnell :) im Vergleich zu dem selben stark Normalisierten Datenmodell.

Ergo: Es ist eben wie so oft die Mischung die's macht ;)

Entwickelt man jedoch ein kleines einfaches System komplett neu (wie etwa ein kleinens Forum ;-) ) so sollte man natürlich Bemüht sein, dass ganze bei der Modellierung mindestens in die dritte Normalform zu bringen und dann wenn's Performance-Technisch wirklich mal klemmt (was bei kleinen Datenbanken so nicht der Fall sein sollte..) kann man sich für die etwaigen Engstellen immernoch Alternativen überlegen...

Gruß Tom
 
Zurück