Comment calculer le rang de centile pour les totaux en points sur différentes périodes?

StackOverflow https://stackoverflow.com/questions/1007146

  •  06-07-2019
  •  | 
  •  

Question

Sur un PHP & amp; Sur un site Web basé sur CodeIgniter, les utilisateurs peuvent acquérir une réputation pour diverses actions similaires à celles de Stack Overflow. Chaque fois que la réputation est attribuée, une nouvelle entrée est créée dans une table MySQL avec id_utilisateur , l'action récompensée et la valeur de cette série de points (par exemple, 10 réputations). En même temps, un champ de la table users , réputation_total , est mis à jour.

Étant donné que tout cela n'a pas de sens sans cadre de référence, je souhaite montrer aux utilisateurs leur rang en centile parmi tous les utilisateurs. Pour une réputation totale, cela semble assez facile. Disons que mon user_id est 1138 . Comptez simplement le nombre d'utilisateurs dans la table users avec un réputation_total inférieur au mien, comptez le nombre total d'utilisateurs et divisez pour trouver le pourcentage d'utilisateurs ayant une réputation inférieure. que le mien. Ce sera le rang centile de l'utilisateur 1138, non? Facile!

Mais j'affiche également les totaux de réputation sur différentes durées, par exemple, au cours des sept derniers jours, ce qui implique d'interroger la table de réputation et de faire la somme de tous mes points gagnés depuis une date donnée. J'aimerais également indiquer le rang de centile pour les différentes durées - par exemple, je suis peut-être le 11e centile au total, mais le 50e centile ce mois-ci et le 97e centile aujourd'hui.

Il semble que je devrais passer en revue et trouver les totaux de réputation de tous les utilisateurs pour la période donnée, puis voir où je me situe dans ce groupe, non? N'est-ce pas terriblement lourd? Quelle est la meilleure façon de faire cela?

Merci beaucoup.

Était-ce utile?

La solution

Je peux penser à quelques options spontanées ici:

  1. Comme vous l'avez dit, additionnez les points de réputation gagnés au cours de la période et calculez les rangs des centiles en fonction de cela.

  2. Suivez quotidiennement les mises à jour de reputation_total. Vous disposez ainsi d'une table avec id_utilisateur, date, total de réputation.

  3. Ajoutez de nouvelles colonnes à la table utilisateur (reputation_total, reputation_total_today, reputation_total_last30days, etc.) pour chaque plage de temps. Vous pouvez également normaliser cette opération dans une table distincte (réputation_totals) pour vous éviter de devoir ajouter une nouvelle colonne à chaque période que vous souhaitez suivre.

L'option n ° 1 est la plus simple, mais elle va probablement devenir lente si vous avez beaucoup de lignes dans votre table de transaction de réputation. Elle ne sera pas très évolutive, surtout si vous devez les calculer en temps réel.

L'option n ° 2 nécessitera davantage de stockage dans le temps (une ligne par utilisateur et par jour), mais serait probablement beaucoup plus rapide que d'interroger directement la table de transactions.

L'option 3 est moins flexible, mais serait probablement l'option la plus rapide.

Les deux options 2 & amp; 3 nécessiterait probablement un traitement par lots pour calculer les totaux sur une base quotidienne, donc il faut également en tenir compte.

Je ne pense pas qu'une option soit nécessairement la meilleure - elles impliquent toutes des compromis différents en termes de vitesse / espace de stockage / complexité / flexibilité. Ce que vous ferez dépendra en définitive des exigences de votre application.

Autres conseils

Je ne vois pas pourquoi ce serait trop complexe. En général, tout ce dont vous avez besoin est d’ajouter à votre clause WHERE une requête qui limite les résultats, par exemple:

WHERE DatePosted between @StartOfRange and @EndOfRange
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top