2009-03-06 11 views
4

Ich arbeite gerade an einem PHP/MySQL-Bewertungssystem. Damit der Benutzer bewerten kann, muss sich der Benutzer anmelden. Jeder Benutzer hat eine eindeutige "UID". Es wird mehrere Bewertungsinstanzen auf der Website geben (eine für jedes Spiel in meinem Fall) und ich brauche eine effiziente Möglichkeit, eine Liste von UIDs in einer MySQL-Zeile zu speichern (eine MySQL-Zeile in der Bewertungstabelle für jede Instanz des Bewertungssystems)) um eine Übersicht zu halten, wer gewählt hat.Beste Methode zum Speichern einer Liste von Benutzer-IDs

Ich habe in anderen Systemen gesehen, dass die Liste in einem serialisierten PHP-Array gespeichert ist. Jedes Mal, wenn ein Benutzer abstimmt, muss das serialisierte Array extrahiert, unserialisiert werden, die neue UID wird eingefügt, das Array wird erneut serialisiert und die MySQL-Zeile wird UPDATEd. Jedes Mal, wenn die Seite geladen wird, muss diese Liste erneut unserialisiert und überprüft werden, um zu sehen, ob der Benutzer, der die Seite anschaut, noch abgestimmt hat, um sicherzustellen, dass der Benutzer nicht zweimal abstimmt.

Dies scheint irgendwie ineffizient und umständlich. Hat MySQL eine integrierte Listenfunktion, um diesen Prozess effizienter zu gestalten? Gibt es cleverere Möglichkeiten, dieses Problem zu beheben?

Ich habe eine mögliche Alternative erwogen, die das Serialisieren vergisst und die UIDs in einem TEXT-Feld in der MySQL-Datenbank speichert. Ich würde einfach nach jeder UID ein nicht-numerisches Zeichen anhängen (sagen wir ein Punkt [.]). Um einen Benutzereintrag hinzuzufügen, würde ich einfach die UID am Ende des TEXT-Felds und dann einen Punkt verketten. Bei der Überprüfung, ob der Benutzer bereits gewählt hat, könnte ich einfach "SELECT * FROM Tabelle WHERE votes = '% $ UID.%';". Würde dies effizienter funktionieren oder gibt es einen eleganteren Weg, die Arbeit zu erledigen?

Follow-up-Post über die Tabellenstruktur ... Efficient MySQL table structure for rating system

Antwort

17

Es ist ineffizient. Was Sie hier in relationalen Begriffen haben, ist eine Viele-zu-Viele-Beziehung zwischen Benutzern und Spielen. Ein Benutzer kann über viele Spiele abstimmen. Über ein Spiel kann von vielen Benutzern abgestimmt werden. Die Lösung dafür ist eine Join-Tabelle zu haben:

USERS (uid, name, ...) 
GAMES (gid, name, ...) 
VOTES (id, uid, gid, ...) 

Wo uid und gid sind Fremdschlüssel zurück zu ihren jeweiligen Tabellen.

Wenn jemand abstimmt, fügen Sie einen Datensatz in VOTES ein.

Um eine Liste der Stimmen für ein Spiel zu bekommen:

$get = mysql_query("SELECT * FROM votes WHERE gid = $game_id"); 
... 

eine Liste der Stimmen des Benutzers zu erhalten:

$get = mysql_query("SELECT * FROM votes WHERE uid = $user_id"); 
... 

und so weiter.

Verbinden Sie kein Array und speichern Sie es in einer einzigen Spalte. Du hast Recht, das zu vermeiden.

+0

Es scheint, dass Sie und Mehrdad den gleichen Ansatz vorschlagen. Ich mache es so. Mein einziges Anliegen ist die Größe der VOTES-Tabelle. Es wäre denkbar, dass <# Spiele x # Nutzer> in dieser Tabelle stimmen würden. Sollte mich das zu meinem Shared Hosting Plan Administrator machen? –

+1

Realistisch gesehen muss eine Tabellengröße in die Millionen gehen, bevor Sie überhaupt eine "Partitionierung" in Betracht ziehen müssen (im Grunde die Daten aufteilen). Der Ansatz, ein Array zu implodieren, wird zwar Zeilen, aber deutlich mehr Overhead für das Lesen und Schreiben haben. – cletus

+1

Wenn Sie die oben aufgeführten Abfragen ausführen, stellen Sie sicher, dass Sie die Tabelle mit * bid * uid und gid indizieren, um die Abfragen schnell zu machen. Das ist der größte Nachteil dieses Ansatzes: Sie benötigen mehrere Indizes. – slacy

4

In einer normalisierten Datenbank, sollten Sie es speichern, in einer Verknüpfungstabelle:

UserRatings 
------------- 
RatingID int 
UserID int 
UserVote int 

Ich weiß nicht, was Ihre Fragen. Abhängig von der Anwendung hat dies möglicherweise nicht die akzeptable Leistung. In jedem Fall schlage ich jedoch vor, dass Sie nur dann mit dem normalisierten Ansatz, Benchmark und Denormalisierung gehen, wenn dies angemessen ist.

Verwandte Themen