45 votes

sélection rapide d'une ligne aléatoire dans une grande table en mysql

Quel est le moyen le plus rapide de sélectionner une ligne aléatoire dans une grande table mysql ?

Je travaille en php, mais je suis intéressé par toute solution, même si elle est dans un autre langage.

48voto

Lasse V. Karlsen Points 148037

Prenez tous les identifiants, choisissez-en un au hasard, et récupérez la ligne complète.

Si vous savez que les identifiants sont séquentiels sans trous, vous pouvez simplement prendre le maximum et calculer un identifiant aléatoire.

S'il y a des trous ici et là mais surtout des valeurs séquentielles, et que vous ne vous souciez pas d'un hasard légèrement biaisé, prenez la valeur maximale, calculez un identifiant et sélectionnez la première ligne avec un identifiant égal ou supérieur à celui que vous avez calculé. La raison de cette distorsion est que les identifiants qui suivent ces trous auront plus de chances d'être sélectionnés que ceux qui suivent un autre identifiant.

Si vous commandez au hasard, vous allez avoir un terrible scan de table sur les bras, et le mot rapide ne s'applique pas à une telle solution.

Ne faites pas cela, et ne commandez pas non plus par un GUID, cela pose le même problème.

37voto

Vinko Vrsalovic Points 116138

Je savais qu'il devait y avoir un moyen de le faire en une seule requête et de manière rapide. Et la voici :

Un moyen rapide sans implication de code externe, bravo à

http://jan.kneschke.de/projects/mysql/order-by-rand/

SELECT name
  FROM random AS r1 JOIN
       (SELECT (RAND() *
                     (SELECT MAX(id)
                        FROM random)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1;

30voto

CesarB Points 18048

MediaWiki utilise une astuce intéressante (pour la fonctionnalité Special:Random de Wikipédia) : la table contenant les articles possède une colonne supplémentaire avec un nombre aléatoire (généré lors de la création de l'article). Pour obtenir un article aléatoire, il faut générer un nombre aléatoire et obtenir l'article dont la valeur est la plus grande ou la plus petite (je ne me souviens plus laquelle) dans la colonne du nombre aléatoire. Avec un index, cela peut être très rapide. (Et MediaWiki est écrit en PHP et développé pour MySQL).

Cette approche peut causer un problème si les nombres résultants sont mal distribués ; IIRC, cela a été corrigé sur MediaWiki, donc si vous décidez de le faire de cette façon, vous devriez jeter un coup d'oeil au code pour voir comment il est actuellement fait (probablement ils régénèrent périodiquement la colonne de nombres aléatoires).

12voto

Bill Karwin Points 204877

Voici une solution qui s'exécute assez rapidement et qui permet d'obtenir une meilleure distribution aléatoire sans dépendre du fait que les valeurs d'identification soient contiguës ou commencent à 1.

SET @r := (SELECT ROUND(RAND() * (SELECT COUNT(*) FROM mytable)));
SET @sql := CONCAT('SELECT * FROM mytable LIMIT ', @r, ', 1');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

3voto

Rob Points 31432

Ajoutez une colonne contenant une valeur aléatoire calculée à chaque ligne, et utilisez-la dans la clause d'ordre, en limitant à un seul résultat lors de la sélection. Cela est plus rapide que de demander à la table d'analyser cette colonne. ORDER BY RANDOM() causes.

Mise à jour : Vous devez toujours calculer une valeur aléatoire avant de lancer l'appel à l'aide. SELECT lors de l'extraction, bien sûr, par ex.

SELECT * FROM `foo` WHERE `foo_rand` >= {some random value} LIMIT 1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X