2010-04-26 13 views
6

J'ai une table MySQL qui a une ligne appelée cur_odds qui est un pourcentage avec la probabilité que cette ligne soit sélectionnée. Comment puis-je faire une requête qui va effectivement sélectionner les lignes dans environ cette fréquence lorsque vous exécutez 100 requêtes par exemple?Sélectionner une rangée aléatoire de MySQL (avec probabilité)

J'ai essayé ce qui suit, mais une ligne ayant une probabilité de 0,35 finit par être sélectionnée dans 60 à 70% des cas. Toutes les valeurs de cur_odds dans la table totalisent exactement 1.

+0

ORDER BY RAND() peut être très lent avec de grands ensembles de données comme c'est O (n log (n)). Combien de lignes aura votre table? –

Répondre

4

Si cur_odds est changé rarement, vous pouvez mettre en œuvre l'algorithme suivant:

1) Créer une autre colonne prob_sum, pour laquelle

prob_sum [0]: = cur_odds [0]

pour 1 < = i = < row_count - 1:

prob_sum [i]: = prob_sum [i - 1] + cur_odds [i]

2) générer un nombre aléatoire entre 0 et 1:

rnd: = rand (0,1)

3) Trouver la première ligne pour laquelle prob_sum > rnd (si vous créer un index de BTREE sur la prob_sum, la requête doit travailler beaucoup plus rapide):

CREER prob_sum_ind INDEX ON < table> (prob_sum);

SET @rnd: = RAND();

SELECT MIN (valeur_sup) FROM < table> WHERE prob_sum> @rnd;

+0

Une meilleure réponse est ici: http://stackoverflow.com/a/12301949/901739 –

3

Compte tenu de votre instruction SQL ci-dessus, quel que soit le nombre que vous avez dans cur_odds sont pas les probabilités que chaque ligne est sélectionnée, mais est plutôt juste une pondération arbitraire (par rapport aux « poids » de toutes les autres lignes) qui pourraient plutôt être interprété comme une tendance relative à flotter vers le haut de la table triée. La valeur réelle de chaque ligne n'a aucun sens (par exemple, vous pourriez avoir 4 lignes avec des valeurs de 0,35, 0,5, 0,75 et 0,99, ou vous pourriez avoir des valeurs de 35, 50, 75 et 99, et les résultats seraient les mêmes).

Mise à jour: Voici ce qui se passe avec votre requête. Vous avez une ligne avec une valeur cur_odds de 0,35. Par souci d'illustration, je vais supposer que les 9 autres lignes ont toutes la même valeur (0.072). Toujours à titre d'exemple, supposons que RAND() renvoie une valeur de 0.0 à 1.0 (il peut en fait).

Chaque fois que vous exécutez cette instruction SELECT, une valeur de tri est affectée à chaque ligne en multipliant sa valeur cur_odds par une valeur RAND() comprise entre 0,0 et 1,0. Cela signifie que la ligne avec un 0.35 aura une valeur de tri entre 0.0 et 0.35.

Chaque ligne (avec une valeur de 0,072) aura des valeurs de tri comprises entre 0,0 et 0,072. Cela signifie qu'il y a environ 80% de chances que votre rangée aura une valeur de tri supérieure à 0,072, ce qui signifierait qu'il n'y a aucune chance que toute autre rangée puisse être triée plus haut. C'est pourquoi votre ligne avec la valeur cur_odds de 0.35 arrive en premier plus souvent que prévu.

J'ai incorrectement décrit la valeur cur_odds comme une pondération de modification relative. Il fonctionne réellement comme une pondération relative maximale, ce qui impliquerait alors des calculs complexes pour déterminer les probabilités relatives réelles impliquées.

Je ne suis pas sûr que ce dont vous avez besoin peut être fait avec T-SQL directement. J'ai mis en œuvre un sélecteur de probabilité pondéré à plusieurs reprises (j'allais même poser une question sur les meilleures méthodes pour ce matin, ironiquement) mais toujours dans le code.

+0

En fait, j'ai 10 lignes, et les 10 valeurs de cur_odds sont égales à 1 exactement. –

+1

Essayez de multiplier toutes les valeurs par 10 (de sorte qu'elles totalisent exactement 10,0) et vous verrez que vous obtenez les mêmes résultats d'ordre. Ou vous pouvez les diviser tous par 3, ou les multiplier par 100 etc. – MusiGenesis