Question

J'ai une table MySQL avec de nombreuses lignes. La table a une colonne de popularité. Si je trier par popularité, je peux obtenir le rang de chaque élément. Est-il possible de récupérer le rang d'un élément particulier sans trier la table entière? Je ne le pense pas. Est-ce exact?

Une alternative serait de créer une nouvelle colonne pour stocker rang, trier la table entière, puis boucle à travers toutes les lignes et mettre à jour le rang. Cela est extrêmement inefficace. Est-il peut-être une façon de le faire en une seule requête?

Était-ce utile?

La solution

Il n'y a aucun moyen de calculer l'ordre (ce que vous appelez le rang) de quelque chose sans avoir d'abord la table de tri ou de stockage de rang.

Si votre table est correctement indexé cependant (indice de popularité), il est trivial pour la base de données pour trier ce que vous pouvez ainsi obtenir votre rang. Je vous suggère quelque chose comme ce qui suit:

Sélectionner tout, y compris le rang

SET @rank := 0;
SELECT t.*, @rank := @rank + 1
FROM table t
ORDER BY t.popularity;

Pour récupérer un élément spécifique avec un « id », alors vous pouvez simplement utiliser une sous-requête comme suit:

Sélectionnez un, y compris rang

SET @rank := 0;
SELECT * FROM (
  SELECT t.*, @rank := @rank + 1
  FROM table t
  ORDER BY t.popularity
) t2
WHERE t2.id = 1;

Autres conseils

Vous avez raison que la deuxième approche est inefficent, si la colonne de rang est mis à jour sur chaque table de lecture. Cependant, selon le nombre de mises à jour il y a à la base de données, vous pouvez calculer le rang de chaque mise à jour, et de stocker que - il est une forme de mise en cache. Vous tournez alors un champ calculé dans un champ de valeur fixe.

Cette vidéo couvre la mise en cache dans une base MySQL, et bien qu'il soit spécifique des rails et est une forme légèrement différente de la mise en cache, est une stratégie de mise en cache très similaire.

Si vous utilisez une table InnoDB, vous pouvez envisager de construire un index cluster sur la colonne de popularité. (Uniquement si l'ordre par la popularité est une requête fréquente). La décision dépend aussi de varier la colonne de popularité est. (0 - 3 pour pas si bon)

Vous pouvez regarder cette info sur index ordonné en clusters pour voir si cela fonctionne pour votre cas: http://msdn.microsoft.com/en-us/library/ms190639.aspx

Il s'agit au serveur SQL, mais le concept est le même, également rechercher la documentation de MySQL à ce sujet.

Si vous faites cela en utilisant PDO alors vous devez modifier la requête à tous être dans la seule instruction afin de le faire fonctionner correctement. Voir PHP / AOP / MySQL: Convertir plusieurs requêtes Dans seule requête

La réponse de hobodave devient quelque chose comme:

SELECT t.*, (@count := @count + 1) as rank
FROM table t 
CROSS JOIN (SELECT @count := 0) CONST
ORDER BY t.popularity;

La solution de hobodave est très bonne. Sinon, vous pouvez ajouter une colonne de rang distinct, puis, chaque fois est UPDATEd la popularité d'une ligne, une requête pour déterminer si cette mise à jour de popularité a changé son classement par rapport à la ligne au-dessus et au-dessous, puis UPDATE les 3 lignes affectées. Vous auriez à profil pour voir quelle méthode est la plus efficace.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top