Je viens de faire un petit test pour les requête imbriqués.
J'ai une table user avec 4 utilisateur dedans, avec un id de 1 à 4.
Puis j'ai lancé plusieurs fois la requête suivante :
Le sous-requête me renvoie un (et un seul) nombre aléatoire compris entre 1 et 4.
En toute logique, on s'attendrait donc à ce que la requête complète nous renvois toujours un seul utilisateur, aléatoirement... ?
Dans les fais, plusieurs fois cette requête m'a renvoyé deux utilisateurs, voir trois.
Qu'est ce qu'il se passe ?
La première partie de la requête (SELECT * FROM user) extrait les 4 utilisateurs de ma table, puis ce résultat est filtré par la clause WHERE... donc pour chaque utilisateur il va tester si l'Id n'est pas dans la résultat de la seconde requête.... qui va donc être exécuté pour chaque utilisateur. Le résultat étant aléatoire, il se peut que 2 voir 3 (et même en théorie les 4) utilisateurs ressortent.
D'où, l'utilisation d'une sous-requête dans un WHERE est extrêmement lent, car si dans votre table utilisateur vous n'en avez pas 4 mais 200, ce sont donc 201 requêtes qui sont exécuté sur la base de donnée pour cet exemple.
(ceci est vrai pour MySQL, pour les autres SGBD je n'en sais rien du tout)
Et comme je suis d'humeur généreuse, voici la parade :
Ici la sous-requête n'est plus dans le WHERE mais directement dans la jointure, elle fait donc partie de la première phase du SELECT et n'est donc exécuté qu'une seule fois... (oui bon, par contre c'est moins lisible)
J'ai une table user avec 4 utilisateur dedans, avec un id de 1 à 4.
Puis j'ai lancé plusieurs fois la requête suivante :
SELECT * FROM `user` WHERE `user_id` IN (SELECT CONVERT(RAND() * 100, UNSIGNED INT) % 4 + 1);
Le sous-requête me renvoie un (et un seul) nombre aléatoire compris entre 1 et 4.
En toute logique, on s'attendrait donc à ce que la requête complète nous renvois toujours un seul utilisateur, aléatoirement... ?
Dans les fais, plusieurs fois cette requête m'a renvoyé deux utilisateurs, voir trois.
Qu'est ce qu'il se passe ?
La première partie de la requête (SELECT * FROM user) extrait les 4 utilisateurs de ma table, puis ce résultat est filtré par la clause WHERE... donc pour chaque utilisateur il va tester si l'Id n'est pas dans la résultat de la seconde requête.... qui va donc être exécuté pour chaque utilisateur. Le résultat étant aléatoire, il se peut que 2 voir 3 (et même en théorie les 4) utilisateurs ressortent.
D'où, l'utilisation d'une sous-requête dans un WHERE est extrêmement lent, car si dans votre table utilisateur vous n'en avez pas 4 mais 200, ce sont donc 201 requêtes qui sont exécuté sur la base de donnée pour cet exemple.
(ceci est vrai pour MySQL, pour les autres SGBD je n'en sais rien du tout)
Et comme je suis d'humeur généreuse, voici la parade :
SELECT * FROM `user`
INNER JOIN (SELECT CONVERT(RAND() * 100, UNSIGNED INT) % 4 + 1 AS `user_id`) AS `rand_user`
USING (`user_id`)
Ici la sous-requête n'est plus dans le WHERE mais directement dans la jointure, elle fait donc partie de la première phase du SELECT et n'est donc exécuté qu'une seule fois... (oui bon, par contre c'est moins lisible)