Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment sélectionner rapidement 3 enregistrements aléatoires dans une table MySQL de 30k avec un filtre where par une seule requête ?

Moche, mais rapide et aléatoire. Peut devenir très moche très vite, surtout avec le réglage décrit ci-dessous, alors assurez-vous que vous le voulez vraiment de cette façon.

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

UNION ALL

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

UNION ALL

(SELECT Products.ID, Products.Name
FROM Products
    INNER JOIN (SELECT RAND()*(SELECT MAX(ID) FROM Products) AS ID) AS t ON Products.ID >= t.ID
WHERE Products.HasImages=1
ORDER BY Products.ID
LIMIT 1)

La première ligne apparaît plus souvent qu'elle ne le devrait

Si vous avez de grands écarts entre les ID dans votre table, les lignes juste après ces écarts auront plus de chances d'être récupérées par cette requête. Dans certains cas, ils apparaîtront beaucoup plus souvent qu'ils ne le devraient. Cela ne peut pas être résolu en général, mais il existe une solution pour un cas particulier courant :lorsqu'il y a un écart entre 0 et le premier ID existant dans une table.

Au lieu de la sous-requête (SELECT RAND()*<max_id> AS ID) utilisez quelque chose comme (SELECT <min_id> + RAND()*(<max_id> - <min_id>) AS ID)

Supprimer les doublons

La requête, si elle est utilisée telle quelle, peut renvoyer des lignes en double. Il est possible d'éviter cela en utilisant UNION au lieu de UNION ALL . De cette façon, les doublons seront fusionnés, mais la requête ne garantit plus de renvoyer exactement 3 lignes. Vous pouvez également contourner ce problème en récupérant plus de lignes que nécessaire et en limitant le résultat externe comme ceci :

(SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
UNION (SELECT ... LIMIT 1)
...
UNION (SELECT ... LIMIT 1)
LIMIT 3

Cependant, il n'y a toujours aucune garantie que 3 lignes seront récupérées. Cela le rend simplement plus probable.