Effiziente SQL-Abfrage / Schema für eine Rangliste

8

Ich habe ein blödes kleines Spiel geschrieben und möchte eine Art Leaderboard-Website haben.

Normalerweise sind die Bestenlisten auf 10 oder 20 Topspieler begrenzt, aber ich dachte, es wäre nett, wenn ich für jeden Spieler seine Top-Punktzahl aufnehmen könnte . Dann könnte ich immer ihren weltweiten Rang anzeigen.

Ein einfaches Schema wie:

%Vor%

Würde die minimale Menge an Informationen speichern, die ich brauche - 1 Eintrag pro Benutzer mit der besten Punktzahl.

Meine Frage dreht sich darum, wie man die Position einer Person auf der Rangliste effizient bestimmen kann. Die allgemeine Idee ist, dass ich ihre Position in der Liste von:

zurückgeben möchte %Vor%

Aber diese Abfrage auszuführen und dann die Liste linear zu durchsuchen, erscheint mir aus der Sicht der DB-Performance etwas lächerlich. Trotzdem habe ich Schwierigkeiten, mir eine Abfrage / ein Schema vorzustellen, die eine schnelle Operation ermöglichen würden.

Irgendwelche Ideen?

(Ich würde es vorziehen, das DB-Schema zu behalten und generische Anfragen abzufragen (nicht an einen Anbieter gebunden.) Aber wenn ein Hersteller dies einfach macht, bin ich glücklich, entweder MS SQL oder MySQL zu verwenden.

    
Frank Krueger 22.02.2009, 21:03
quelle

7 Antworten

13

Wie wäre es mit:

%Vor%

Sie möchten auch einen Index für die Punkte-Spalte.

Wenn Sie count()+1 mit score > (...) tun, erhalten Sie genaue Ränge, auch wenn mehrere Spieler die gleiche Punktzahl haben. doing count() mit score >= (...) wird nicht.

    
Henning 22.02.2009, 21:07
quelle
2

Ab SQL Server 2005 können Sie das RANK() Funktion, um den Rang für jeden Benutzer basierend auf seiner Punktzahl zurückzugeben

%Vor%

Wenn Sie mehr als einen Typ von "Spieltyp" hatten, können Sie dies in die Tabelle Leaderboard aufnehmen und die PARTITION BY -Klausel in der Funktion RANK verwenden, um die Rangfolge für jeden Spieltyp zu bestimmen.

    
Russ Cam 22.02.2009 22:06
quelle
1

Die naheliegende Option wäre, einen Index für "Score" zu erstellen, was völlig in Ordnung ist. (Es klingt, als ob Sie zwei Werte beibehalten möchten - kumulative Punktzahl und High-Water-Punktzahl - oder ich missverstehe sonst?)

Wenn Sie nicht Zehntausende von Benutzern erwarten, sollten selbst Tabellen-Scans in einer Tabelle mit diesen vielen Datensätzen kein großes Problem darstellen.

    
dkretz 22.02.2009 21:06
quelle
1

Wenn dies nicht in Echtzeit erfolgen muss (z. B. wenn die Aktualisierung einmal pro Tag akzeptabel ist), fügen Sie ein zusätzliches "Position" -Feld hinzu und aktualisieren Sie es regelmäßig mit einer nach Punkten sortierten Abfrage.

    
MaxVT 22.02.2009 21:20
quelle
1

Sieht so aus, als wollten Sie das abfragen:

%Vor%

Dies gibt die Bestenliste mit 1 Eintrag für jeden Benutzer zurück.

BEARBEITEN SIE UNTEN: Ich sehe in dem Kommentar, dass Sie den Rang sehen wollen, nicht das Ergebnis. dafür kenne ich die ANSI SQL Antwort nicht, aber datenbankspezifisch:

In MySQL:

%Vor%

In Oracle können Sie die RANK-Anweisung verwenden.

    
Edwin 22.02.2009 21:14
quelle
1

In SQL Server 2005 erledigt Rank () ziemlich genau die Aufgabe für Sie. Aber wenn du Millionen von Datensätzen hast, dann rangiere sie in Echtzeit, wenn sich die zugrunde liegenden Werte ändern, wird das Performance-Schwein.

Ich habe versucht, eine indexierte Ansicht oberhalb der ausgewählten Abfrage zu erstellen ... (die gewählte Antwort in diesem Thread), aber Sql 2005 ließ mich das nicht erstellen, weil Sie keine Unterabfragen, Selbstreferenz in einer indizierten Sicht verwenden können.

Unsere Problemumgehung besteht also darin, die Rangliste allabendlich mit der Funktion Row () zu aktualisieren. Um das Blockieren während dieses Updates zu vermeiden, bewahren wir 2 Kopien der Rangliste auf, die aktualisiert und in der Anwendung verwendet werden. Wir haben eine RankingView, die zu jeder Zeit auf die aktive Rangliste zeigt.

Ich würde gerne wissen, ob es eine Lösung für Echtzeit-Ranking-Update für wirklich große Tabellen gibt?

    
Nikhil S 30.07.2009 23:19
quelle
0

Ich habe über das select nachgedacht "Anzahl (*) + 1 als Rang vom Leaderboard auswählen wo Punkt & gt; (Wählen Sie den Punktestand aus der Bestenliste, wo userid =?) "

Denken Sie an die folgende Situation: Spieler 1, 100 Punkte Spieler 2, 100 Punkte Spieler 3, Ergebnis 50

Mit diesem SQL wäre der Rang von Spieler 3 3, wobei die richtige Antwort 2 sein sollte, weil Spieler 1 und Spieler 2 an der ersten Position gebunden sind. Die Aggregatfunktion count () berücksichtigt in diesem Fall 2 Datensätze mit Score-Spalte & gt; 50.

Um diesen Fall zu behandeln, denke ich, dass die richtige Option darin besteht, eine Gruppe zu bilden, so dass wiederholbare Werte der Punkte als eine einzige Rangposition behandelt werden:

%Vor%     
Marcus Vinicius de LIma 26.02.2015 21:44
quelle

Tags und Links