Bonsoir,
Je fais ce post parce que ça intéressera peut-être certains (j'ai pas vraiment vu de solution clé en main sur le forum) mais aussi pour avoir d'éventuelles améliorations à ma méthode, et peut-être des réponses à mes interrogations. J'ai donc essayé trois méthodes pour faire un tirage aléatoire dans une table.
Méthode 1
J'avais l'habitude de faire une requête dans ce genre pour avoir une ligne aléatoire dans ma table :
C'est une jolie solution en MySQL pur mais le temps d'exécution augmente grandement avec le nombre de lignes. Le ORDER BY rand() oblige MySQL à tirer un nombre aléatoire pour chaque ligne puis à les trier et enfin renvoyer la première. C'est très lourd et aucun index ne peut accélérer les choses. Il n'y a pas de cache MySQL possible.
J'ai fait un test avec 10 requêtes consécutives :
Temps première : 62ms
Temps suivantes : 62ms
Pour faire un vrai tirage aléatoire avec des lignes ayant des id non nécessairement consécutifs, on est obligé de passer par php.
Méthode 2
Ma première idée était de faire ça :
Mais ici le temps gagné sur la requête (utilisation d'index et de cache par MySQL), on le perd sur le traitement du gros résultat avec toutes les lignes. La table ma_table est une table avec des champs text donc la récupération de toutes les lignes est très coûteuse. Ça peut être une bonne solution avec des lignes légères (sans texte et pas beaucoup de colonnes).
Temps première : 45ms
Temps suivantes : 45ms (Je comprends pas trop pourquoi il n'y a pas un cache qui accélère les requêtes suivantes...)
Méthode 3
Finalement, voilà comment je procède :
Ici, la requête est rapide (avec index et cache) le volume de données est réduit au max (une colonne de int). Php tire un seul nombre aléatoire et la dernière requête est aussi extrêmement rapide (index et cache).
Temps première : 19ms
Temps suivantes : 0.7ms
La dernière solution est donc bien la plus rapide on gagne un facteur de 3 à 90 par rapport à la première solution.
J'ai juste une question concernant cette dernière méthode, pourquoi lorsque je recharge ma page de test, la première requête n'est pas plus rapide ? N'est-elle pas en cache ? Le cache mysql est-il propre à chaque connexion ?
N'hésitez pas à me dire s'il y a un truc qui va pas dans mes explications, ou si vous avez une méthode plus efficace.
Je fais ce post parce que ça intéressera peut-être certains (j'ai pas vraiment vu de solution clé en main sur le forum) mais aussi pour avoir d'éventuelles améliorations à ma méthode, et peut-être des réponses à mes interrogations. J'ai donc essayé trois méthodes pour faire un tirage aléatoire dans une table.
Méthode 1
J'avais l'habitude de faire une requête dans ce genre pour avoir une ligne aléatoire dans ma table :
Code:
$sql = "SELECT tous_les_champs_dont_j_ai_besoin
FROM ma_table
WHERE conditions
ORDER BY rand()
LIMIT 1";
$requet = mysql_query($sql);
$data = mysql_fetch_assoc($requet);
C'est une jolie solution en MySQL pur mais le temps d'exécution augmente grandement avec le nombre de lignes. Le ORDER BY rand() oblige MySQL à tirer un nombre aléatoire pour chaque ligne puis à les trier et enfin renvoyer la première. C'est très lourd et aucun index ne peut accélérer les choses. Il n'y a pas de cache MySQL possible.
J'ai fait un test avec 10 requêtes consécutives :
Temps première : 62ms
Temps suivantes : 62ms
Pour faire un vrai tirage aléatoire avec des lignes ayant des id non nécessairement consécutifs, on est obligé de passer par php.
Méthode 2
Ma première idée était de faire ça :
Code:
$sql = "SELECT tous_les_champs_dont_j_ai_besoin
FROM ma_table
WHERE conditions"; // On prend toutes les données de toutes les lignes
$requet = mysql_query($sql1);
$r = rand(0,mysql_num_rows($requet) - 1); // On tire une ligne au hasard
mysql_data_seek($requet, $r);
$data = mysql_fetch_assoc($requet);
Temps première : 45ms
Temps suivantes : 45ms (Je comprends pas trop pourquoi il n'y a pas un cache qui accélère les requêtes suivantes...)
Méthode 3
Finalement, voilà comment je procède :
Code:
$sql0 = "SELECT id
FROM ma_table
WHERE conditions"; // On ne prend que les ids
$requet0 = mysql_query($sql0);
$r = rand(0,mysql_num_rows($requet0) - 1); // On tire une ligne au hasard
mysql_data_seek($requet0, $r);
$data0 = mysql_fetch_assoc($requet0);
$id = $data0['id'];
$sql = "SELECT tous_les_champs_dont_j_ai_besoin
FROM ma_table
WHERE id = '$id'"; // On va chercher toutes les données de la ligne dans la table
$requet = mysql_query($sql);
$data = mysql_fetch_assoc($requet);
Temps première : 19ms
Temps suivantes : 0.7ms
La dernière solution est donc bien la plus rapide on gagne un facteur de 3 à 90 par rapport à la première solution.
J'ai juste une question concernant cette dernière méthode, pourquoi lorsque je recharge ma page de test, la première requête n'est pas plus rapide ? N'est-elle pas en cache ? Le cache mysql est-il propre à chaque connexion ?
N'hésitez pas à me dire s'il y a un truc qui va pas dans mes explications, ou si vous avez une méthode plus efficace.