Sobes.tech
Middle+

Comment optimiser l'opérateur ORDER BY RAND() ?

sobes.tech IA

Réponse de l'IA

Optimiser ORDER BY RAND() est difficile, car il nécessite une sélection complète des données pour générer un nombre aléatoire pour chaque ligne. Les approches typiques :

  1. Sélection d'un identifiant aléatoire :

    • Obtenir le nombre de lignes dans la table.
    • Générer un nombre aléatoire entre 0 et N-1 (ou 1 et N).
    • Sélectionner la ligne avec le décalage correspondant ou OFFSET.
    SELECT COUNT(*) FROM your_table;
    -- Supposé que le nombre total de lignes = N
    
    SELECT * FROM your_table LIMIT 1 OFFSET floor(random() * N);
    

    Cette méthode convient pour sélectionner une ou quelques lignes aléatoires. Elle n'est pas efficace pour un grand nombre de lignes.

  2. Sélection aléatoire par plage de id :

    • Trouver le id minimum et maximum.
    • Générer un nombre aléatoire dans cette plage.
    • Sélectionner la ligne avec id >= nombre_aleatoire, en utilisant LIMIT.
    SELECT MIN(id), MAX(id) FROM your_table;
    -- Supposé que min_id, max_id ont été obtenus
    
    -- Dans l'application, générer un id aléatoire dans la plage [min_id, max_id]
    -- Par exemple : id_aleatoire = min_id + floor(random() * (max_id - min_id + 1))
    
    SELECT * FROM your_table WHERE id >= id_aleatoire LIMIT 1;
    

    Peut sauter des lignes si des trous existent dans id.

  3. Création d'une table temporaire ou utilisation d'une sous-requête avec tri par nombre aléatoire :

    • Sélectionner un sous-ensemble de données ou uniquement id dans une sous-requête.
    • Appliquer ORDER BY RAND() à ce sous-ensemble.
    SELECT *
    FROM your_table AS t1 JOIN (SELECT id FROM your_table ORDER BY RAND() LIMIT 100) AS t2
    ON t1.id = t2.id;
    

    Réduit la charge si LIMIT est appliqué à la sous-requête.

  4. Utilisation d'un champ supplémentaire avec un nombre aléatoire :

    • Ajouter un champ dans la table pour stocker un nombre aléatoire.
    • Mettre à jour périodiquement ce champ pour toutes les lignes.
    • Trier par ce champ.
    -- Ajouter un champ
    ALTER TABLE your_table ADD random_sort_key FLOAT;
    
    -- Mise à jour périodique
    UPDATE your_table SET random_sort_key = RAND();
    
    -- Sélection
    SELECT * FROM your_table ORDER BY random_sort_key LIMIT 10;
    

    Nécessite des modifications dans le schéma et dans le processus de mise à jour en arrière-plan.

  5. Algorithme de "mélange" (Fisher-Yates) hors de la base de données :

    • Sélectionner tous les id (ou toutes les données si elles sont petites).
    • Mélanger la liste dans l'application.
    • Sélectionner les N premiers éléments.
    // Supposé que ids est []int
    // ids = ... // Obtenir les ids depuis la base de données
    
    rand.Shuffle(len(ids), func(i, j int) {
        ids[i], ids[j] = ids[j], ids[i]
    })
    
    // Les N premiers éléments de ids sont maintenant aléatoires
    // Ils peuvent être utilisés pour sélectionner des lignes complètes
    // SELECT * FROM your_table WHERE id IN (...)
    

    Convient uniquement pour des tables avec peu de lignes.

Le choix de la méthode optimale dépend de la taille de la table, du nombre de lignes aléatoires nécessaires et du SGBD spécifique. Pour la plupart des cas, lorsque vous devez sélectionner un petit nombre de lignes aléatoires dans une grande table, la combinaison d'obtention des id avec un OFFSET ou WHERE id IN (...) sera plus performante que ORDER BY RAND() en ordre direct.