La sélection de lignes aléatoires est toujours délicate, et il n'y a pas de solutions parfaites qui n'impliquent pas de compromis. Soit compromettre les performances, soit compromettre même la distribution aléatoire, soit compromettre la possibilité de sélectionner des doublons, etc.
Comme @JakeGould le mentionne, toute solution avec ORDER BY RAND()
n'évolue pas bien. Au fur et à mesure que le nombre de lignes dans votre table augmente, le coût du tri de toute la table dans un tri de fichiers devient de plus en plus lourd. Jake a raison de dire que la requête ne peut pas être mise en cache lorsque l'ordre de tri est aléatoire. Mais je m'en fiche un peu car je désactive généralement le cache de requêtes de toute façon (il a ses propres problèmes d'évolutivité).
Voici une solution pour pré-randomiser les lignes du tableau, en créant une colonne rownum et en attribuant des valeurs consécutives uniques :
ALTER TABLE products ADD COLUMN rownum INT UNSIGNED, ADD KEY (rownum);
SET @rownum := 0;
UPDATE products SET rownum = (@rownum:[email protected]+1) ORDER BY RAND();
Vous pouvez maintenant obtenir une ligne aléatoire par une recherche d'index, sans tri :
SELECT * FROM products WHERE rownum = 1;
Ou vous pouvez obtenir la ligne aléatoire suivante :
SELECT * FROM products WHERE rownum = 2;
Ou vous pouvez obtenir 10 lignes aléatoires à la fois, ou tout autre nombre que vous voulez, sans doublons :
SELECT * FROM products WHERE rownum BETWEEN 11 and 20;
Vous pouvez re-randomiser à tout moment :
SET @rownum := 0;
UPDATE products SET rownum = (@rownum:[email protected]+1) ORDER BY RAND();
Il est toujours coûteux de faire le tri aléatoire, mais maintenant vous n'avez plus à le faire sur chaque requête SELECT. Vous pouvez le faire selon un horaire, de préférence aux heures creuses.