Différence entre deux Requêtes

Différence entre deux Requêtes - SQL/NoSQL - Programmation

Marsh Posté le 30-12-2009 à 23:01:00    

Bonjour à tous,
 
J'aimerais savoir la différence entre ces deux requête mysql :
 
- SELECT * FROM produit P, rubrique R WHERE P.id_produit = R.id_produit AND R.id_rubrique = 'legumes' ;
 
- SELECT * FROM produit WHERE id_produit IN (SELECT id_produit FROM rubrique WHERE id_rubrique = 'legumes') ;
 
Peut-on également faire une sous-requête sur une même table ?
 
- SELECT id_produit FROM produit WHERE id_produit IN (SELECT id_produit FROM produit WHERE description_produit = 'pain') ;
 
Cela paraît ridicule mais ça me permettrais d'éviter de mettre deux WHERE à la suite ce qui n'est pas possible il me semble.
 
Merci pour vos réponses.
 

Reply

Marsh Posté le 30-12-2009 à 23:01:00   

Reply

Marsh Posté le 30-12-2009 à 23:55:59    

oh putain [:mlc]
si tu veux éviter les WHERE à la con, renseigne toi sur les jointures via le mot clé JOIN, et recherche mes interventions sur la cat SQL qui fustigent les jointures par WHERE


---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 31-12-2009 à 09:16:26    

Cf le lien de ma signature ( :ange: )


Message édité par MagicBuzz le 31-12-2009 à 09:16:32
Reply

Marsh Posté le 31-12-2009 à 10:03:50    

The Murderer a écrit :

SELECT id_produit FROM produit WHERE id_produit IN (SELECT id_produit FROM produit WHERE description_produit = 'pain') ;


[:prozac]  
Tu te rends compte que ta requête revient à  

Code :
  1. SELECT id_produit FROM produit WHERE description_produit = 'pain'


 

The Murderer a écrit :

ça me permettrais d'éviter de mettre deux WHERE à la suite ce qui n'est pas possible il me semble.


Peux-tu developper ?


---------------
Software and cathedrals are much the same - first we build them, then we pray.
Reply

Marsh Posté le 31-12-2009 à 10:16:04    

Harkonnen a écrit :

oh putain [:mlc]
si tu veux éviter les WHERE à la con, renseigne toi sur les jointures via le mot clé JOIN, et recherche mes interventions sur la cat SQL qui fustigent les jointures par WHERE


+1
Where c'est pour les restrictions, join pour les jointures.
La bonne requete (la premiere) est donc :

Code :
  1. SELECT *
  2. FROM produit P JOIN rubrique R  ON P.id_produit = R.id_produit
  3. WHERE  R.id_rubrique = 'legumes' ;


La deuxieme est a eviter, les perfs du 'in' equivallent au or sont degeulasses en general et peuvent ne pas utiliser d'index. Si tu tiens quand meme a l'utiliser, mets au moins un distinct dans le sous select ou plutot prefere utiliser un clause 'exists' souvent moins penalisante :

Code :
  1. SELECT *
  2. FROM produit P
  3. WHERE EXISTS ( SELECT NULL FROM rubrique R WHERE p.id_produit = r.id_produit and id_rubrique = 'legumes') ;


mais c'est nettement moins performant qu'une jointure.
Quand a la derniere, anapajari a tout dit, il est souvent plus simple d'enrichir la clause where que de faire des auto-sous-jointures a la mord moi le noeud.

Reply

Marsh Posté le 31-12-2009 à 10:18:52    

Pour la diff entre IN et EXISTS, je tenais le même discourt.
Finalement, après différents tests (cf. ma signature) j'ai du admettre que Oracle et Microsoft tout du moins, on particulièrement beaucoup travaillés sur le IN, qui est étonnamment souvent plus rapide que le EXISTS (moi aussi ça m'a laissé sur le derrière)

Reply

Marsh Posté le 31-12-2009 à 11:25:42    

Oui, c'est en partie vrai car les in sont automatiquement transformes en 'union' depuis un certain temps par ces deux systemes.  
Par contre, si tu lis bien le sujet, c'est du mysql et mysql est une vraie merde de ce cote.
Compare une requete avec des or et une union (meme perfs oracle et sqlserveur a peu de chose pres) aux variantes mysql et pleure si tu utilise ce dernier.
 
==> Edit grammaire et orthographe trop pitoyables pour rester en l'etat meme si ce n'est pas encore parfait.

Message cité 1 fois
Message édité par fred777888999 le 31-12-2009 à 11:28:39
Reply

Marsh Posté le 31-12-2009 à 11:55:20    

fred777888999 a écrit :

les perfs du 'in' equivallent au or sont degeulasses en general et peuvent ne pas utiliser d'index.


fred777888999 a écrit :

Oui, c'est en partie vrai car les in sont automatiquement transformes en 'union' depuis un certain temps par ces deux systemes.


Source ou explication pour ces deux points, ça m'interesse :o  


---------------
Software and cathedrals are much the same - first we build them, then we pray.
Reply

Marsh Posté le 31-12-2009 à 13:48:03    

anapajari a écrit :


[:prozac]  
Tu te rends compte que ta requête revient à  

Code :
  1. SELECT id_produit FROM produit WHERE description_produit = 'pain'


 


 

anapajari a écrit :


Peux-tu developper ?


 
Merci pour vos réponses !!
 
En fait, j'ai une requête assez complexe à ecrire et je suis un peu perdu.
 
J'aimerais joindre plusieurs tables :  
 
-Table rubrique --> id_rubrique//nom_rubrique
-Table rubrique_sup --> id_rubrique//id_rub_sup
-Table rubriques_produits --> id_rubrique//id_produit
-Table produit --> id_produit//libelle_produit//prix_produit
 
J'aimerais connaitre le nom des rubriques (nom_rubrique) ayant pour rubrique supérieure 2 (id_rub_sup = '2') et contenant tout les produits répondants a un certain mot clé.
 
J'ai essayé de l'ecrire comme ceci :
 
 SELECT * FROM rubrique R JOIN rubrique_sup RS ON R.id_rubrique = RS.id_rubrique  
 WHERE RS.id_rub_sup = '.$idsup.' AND R.id_rubrique IN (SELECT RP.id_rubrique FROM rubriques_produit RP JOIN rubrique R ON RP.id_rubrique = R.id_rubrique WHERE RP.id_rubrique  
 IN (SELECT DISTINCT id_rubrique FROM rubriques_produit WHERE id_produit  
 IN (SELECT DISTINCT id_produit MATCH (libelle_produit) AGAINST ('.$rech.')
 FROM produit WHERE MATCH (libelle_produit) AGAINST ('.$rech.'))))' ;  
 
Je ne sais pas quand utiliser des IN et quand utiliser des JOIN sachant que cela se ressemble j'ai l'impression.  
 
De plus je veux la jointure des rubriques ayant telle rub_sup et des rubriques ayant tels produits et je ne pense pas ici que le AND soit le bon mot.
 
Merci pour votre aide.

Reply

Marsh Posté le 31-12-2009 à 14:09:02    

Ben c'est que des jointures que je vois dans ton truc, la requete est elementaire...

Code :
  1. SELECT R.*
  2. FROM rubrique R
  3. JOIN rubrique_sup s ON s.id_rubrique = R.id_rubrique
  4. JOIN rubriques_produit RP ON rp.id_rubrique = R.id_rubrique
  5. JOIN produit P ON p.id_produit = rp.id_produit
  6. WHERE S.id_rub_sup = 2
  7. AND MATCH(p.libelle_produit) AGAINST '$rech'


ou alors qq chose de simple m'as echape mais je ne vois pas quoi ?

Reply

Marsh Posté le 31-12-2009 à 14:09:02   

Reply

Marsh Posté le 31-12-2009 à 14:09:43    

Tu peux ajouter un distinct pour eviter d'avoir les rubriques en doublons, ce sera plus propre...

Reply

Marsh Posté le 31-12-2009 à 14:14:47    

Code :
  1. SELECT r.nom, count(p.*) nb
  2. FROM rubrique r
  3. INNER JOIN rubrique_sup rs ON rs.id_rubrique = r.id_rubrique
  4. INNER JOIN rubriques_produit rp ON rp.id_rubrique = r.id_rubrique
  5. INNER JOIN produit p ON p.id_produit = rp.id_produit
  6. WHERE rs.id_rub_sup = $idsup
  7. AND match(p.libelle_produit) against ($rech)
  8. ORDER BY 1 DESC
 

A noter que je ne suis pas sûr de la syntaxe du MATCH() AGAINST() que je n'utilise pas (je travaille jamais sur MySQL)

 

En tout cas, à ce détail près, t'as rien de plus compliqué que ça dans ta requête...

 

Grrrr, grillé par fred :o


Message édité par MagicBuzz le 31-12-2009 à 14:15:15
Reply

Marsh Posté le 31-12-2009 à 14:18:47    

==> surtout tu as oublie le group_by pour ta fonction de comptage, on va mettre ca sur le compte du nouvel an :)

Reply

Marsh Posté le 31-12-2009 à 14:38:21    

anapajari a écrit :


Source ou explication pour ces deux points, ça m'interesse :o  


Si tu as mysql, oracle et/ou sql-serveur, le test est tres facile a faire...

Code :
  1. SELECT * FROM table T WHERE T.clef = 'valeur'


Utilise l'index

Code :
  1. SELECT * FROM table T WHERE T.clef = 'valeur'
  2. UNION
  3. SELECT * FROM table T WHERE T.clef = 'valeur2'


l'utilise aussi

Code :
  1. SELECT * FROM table T WHERE T.clef IN ('valeur', 'valeur1')


ou

Code :
  1. SELECT * FROM table T WHERE ((T.clef = 'valeur') OR (T.clef= 'valeur1'))


fait un magnifique full scan en mysql, mais utilise bien l'index en oracle ou sqlserveur. J'en suis tombe sur le cul quand une des pages d'un de nos sites rammait a mort suite a la modif d'un collegue qui avait rajoute un or sur un colonne de clef primaire.
Ce truc est Ok en oracle depuis la version 8 au moins :)  
Je n'ai pas verifie si c'etait vrai avec tous les moteurs mysql ou seulement celui qu'on utilisait (je ne sais plus lequel c'etait).

Reply

Marsh Posté le 31-12-2009 à 14:38:37    

fred777888999> c'est possible mon explication ou pas ? (cf mon post plus haut), merci :)


---------------
Software and cathedrals are much the same - first we build them, then we pray.
Reply

Marsh Posté le 31-12-2009 à 14:39:41    

:) up :)

Reply

Marsh Posté le 31-12-2009 à 14:56:16    

fred777888999 a écrit :

==> surtout tu as oublie le group_by pour ta fonction de comptage, on va mettre ca sur le compte du nouvel an :)


Et sur le fait que ça doit faire 6 mois que j'ai pas écrit une seule requête :D

Reply

Marsh Posté le 31-12-2009 à 15:27:25    

fred777888999 a écrit :


Si tu as mysql, oracle et/ou sql-serveur, le test est tres facile a faire...
[...]
Je n'ai pas verifie si c'etait vrai avec tous les moteurs mysql ou seulement celui qu'on utilisait (je ne sais plus lequel c'etait).


C'est pas le cas sur une 5.0.37 :o

EXPLAIN EXTENDED select * from maTable where monChamps=1 or monChamps=2;
--
id,  select_type,  table,   type,   possible_keys,  key,   key_len,  ref,   rows,  Extra
1,  'SIMPLE',  'maTable',  'range',  'PRIMARY',  'PRIMARY',  '4',   '',   2,  'Using where'

 

EXPLAIN EXTENDED select * from maTable where monChamps in (1,2);
--
id,  select_type,  table,   type,   possible_keys,  key,   key_len,  ref,   rows,  Extra
1,  'SIMPLE',  'maTable',  'range',  'PRIMARY',  'PRIMARY',  '4',   '',   2,  'Using where'

 

EXPLAIN EXTENDED select * from maTable where monChamps=1 union select * from maTable where monChamps = 2;
--
id,  select_type,  table,   type,   possible_keys,  key,   key_len,  ref,   rows,  Extra
1,  'PRIMARY',  'maTable',  'const',  'PRIMARY',  'PRIMARY',  '4',   'const',  1,  ''
2,  'UNION',  'maTable',  'const',  'PRIMARY',  'PRIMARY',  '4',   'const',  1,  ''
,  'UNION RESULT', '<union1,2>',  'ALL',   '',   '',   '',   '',   ,  ''

 

Par ailleurs sur le point oracle (conversion in => union), j'ai trouvé ça qui montrerait plutot que l'optimizer transforme les in/exists en join (et pas en union)...


Message édité par anapajari le 31-12-2009 à 15:28:13

---------------
Software and cathedrals are much the same - first we build them, then we pray.
Reply

Marsh Posté le 31-12-2009 à 15:41:14    

Effectivement, ton or est correctement fait, mais je peux t'assurer que ce n'etait pas le cas sur l'optimisation qu'on a du faire :( J'en ai donc tire abusivement la conclusion que mysql ne faisait JAMAIS l'optimisation alors que ce n'est visiblement pas le cas.  
Merci de cette precision :)
Pour le second point, oui, bien sur, il faut bien faire une jointure sous la sous-requete avant de faire l'union ensuite pour ramener les deux lignes du exists. Mais je t'accorde volontier que le terme 'transforme en union' est un abus de language juste pour rendre l'idee comprehensible.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed