2009-08-18 6 views
-1

This question demande comment sélectionner le rang d'un utilisateur par son identifiant.Optimisation db: classement informatique

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

La réponse est acceptée

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

ce qui est logique. J'aimerais comprendre ce que seraient les compromis de performance entre cette approche ou en modifiant la structure db pour stocker un rang calculé (je suppose que cela nécessiterait des changements massifs chaque fois qu'il y a un changement de rang), ou toute autre approche que je Je suis trop nouveau pour y penser. Je suis un db noob.

Répondre

1

Le compromis entre performance serait essentiellement ce que vous avez décrit:

Si vous avez modifié la structure pour stocker un rang, les requêtes seraient très, très simple et rapide. Cependant, cela nécessiterait des frais généraux chaque fois que les «points» changeraient, car vous devrez vérifier que le rang n'a pas changé. Si le classement avait changé, vous auriez à faire plusieurs mises à jour.

Cela provoque plus de travail (avec la possibilité de bogues) à chaque mise à jour/insertion. Le compromis est très rapide. Si vous utilisez typiquement peu de modifications par rapport à des millions de lectures, ET que vous avez trouvé que cette requête est un goulot d'étranglement, il pourrait être utile d'envisager de la retravailler. Cependant, j'éviterais les problèmes de complexité et de maintenabilité à moins que vous ne trouviez vraiment que cela pose problème, car la solution actuelle nécessite moins de stockage et est très flexible.

0

La partie "where" de cette requête ne nécessite-t-elle pas en interne la lecture de la table entière? Je comprends l'optimisation prématurée. Sur le plan académique, il semble que cela ne dépasse pas quelques milliers de lignes.

1

Le lien auquel vous faites référence est une question MySQL. Si la base de données originale avait été Oracle, la réponse acceptée serait d'utiliser une fonction analytique, qui évolue très bien:

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>