2009-08-18 11 views
-1

This question fragt, wie man den Rang eines Benutzers anhand seiner ID auswählt.db-optimierung: computing rank

id  name  points 
1  john  4635 
3  tom  7364 
4  bob  234 
6  harry 9857 

Die akzeptierte Antwort ist

SELECT uo.*, 
     (
     SELECT COUNT(*) 
     FROM users ui 
     WHERE (ui.points, ui.id) >= (uo.points, uo.id) 
     ) AS rank 
FROM users uo 
WHERE id = @id 

, die Sinn macht. Ich würde gern verstehen, was die Performance-Kompromisse sein würden, zwischen diesem Ansatz oder durch Modifizieren der db-Struktur, um einen berechneten Rang zu speichern (ich nehme an, dass jedes Mal massive Änderungen erforderlich wären, wenn eine Rangänderung stattfindet) oder andere Ansätze, die ich bin zu neu, um daran zu denken. Ich bin ein db noob.

Antwort

1

Die Leistung Kompromiss wäre im Grunde das, was Sie beschrieben:

Wenn Sie die Struktur modifizieren, um einen Rang zu speichern, Abfragen sehr sein würden, sehr einfach und schnell. Dies würde jedoch bei jeder Änderung von "Punkten" etwas Overhead erfordern, da Sie sicherstellen müssten, dass sich der Rang nicht geändert hat. Wenn sich das Ranking geändert hat, müssen Sie mehrere Updates durchführen.

Dies verursacht mehr Arbeit (mit dem Potenzial für Fehler) bei jedem Update/Einfügung. Der Kompromiss ist sehr schnell zu lesen. Wenn Sie eine typische Verwendung verwenden, sind nur wenige Änderungen im Vergleich zu Millionen von Lesevorgängen, und wenn Sie diese Abfrage als Engpass gefunden haben, könnte es eine Überlegung wert sein, dies zu überarbeiten. Ich würde jedoch die zusätzlichen Probleme in Bezug auf Komplexität und Wartbarkeit vermeiden, es sei denn, Sie haben wirklich festgestellt, dass dies ein Problem ist, da die aktuelle Lösung weniger Speicherplatz benötigt und sehr flexibel ist.

0

Benötigt der 'where' Teil dieser Abfrage intern nicht die gesamte Tabelle? Ich verstehe über vorzeitige Optimierung. Akademisch scheint es, dass dies nicht weiter als ein paar tausend Zeilen skalieren würde.

1

Der Link, auf den Sie verweisen, ist eine MySQL-Frage. Wenn die ursprüngliche Datenbank Oracle gewesen wäre, wäre die akzeptierte Antwort, eine analytische Funktion zu verwenden, die sehr schön skaliert:

SQL> select id, name, points from users order by id 
    2/

     ID NAME   POINTS 
---------- ---------- ---------- 
     1 john    4635 
     3 tom    7364 
     4 bob    234 
     6 harry   9857 
     8 algernon   1 
     9 sebastian   234 
     10 charles   888 

7 rows selected. 

SQL> select name, id, points, rank() over (order by points) 
    2 from users 
    3/

NAME    ID  POINTS RANK()OVER(ORDERBYPOINTS) 
---------- ---------- ---------- ------------------------- 
algernon   8   1       1 
bob     4  234       2 
sebastian   9  234       2 
charles   10  888       4 
john    1  4635       5 
tom     3  7364       6 
harry    6  9857       7 

7 rows selected. 

SQL> select name, id, points, dense_rank() over (order by points desc) 
    2 from users 
    3/

NAME    ID  POINTS DENSE_RANK()OVER(ORDERBYPOINTSDESC) 
---------- ---------- ---------- ----------------------------------- 
harry    6  9857         1 
tom     3  7364         2 
john    1  4635         3 
charles   10  888         4 
bob     4  234         5 
sebastian   9  234         5 
algernon   8   1         6 

7 rows selected. 

SQL>