Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2666 connectés 

  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  Mysql : requete avec EXISTS

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Mysql : requete avec EXISTS

n°1483621
bb007
Posté le 29-11-2006 à 11:30:19  profilanswer
 

Bonjour,
 
Voici ma requete qui doit afficher les annonces comprenant des photos. Le problème est que cette requete affiche aussi les annonces qui n'en n'ont pas...
 
Alors que SELECT * FROM vues, annonces WHERE annonces.id_annonce = vues.id_annonce affiche toutes les annonces qui ont des photos.
 
Je pense que ça vient de la clause EXISTS mais je ne vois pas pourquoi.
 
 
SELECT *
FROM annonces
WHERE
EXISTS (
SELECT *
FROM vues, annonces
WHERE annonces.id_annonce = vues.id_annonce
)
LIMIT 0 , 30

mood
Publicité
Posté le 29-11-2006 à 11:30:19  profilanswer
 

n°1483652
anapajari
s/travail/glanding on hfr/gs;
Posté le 29-11-2006 à 11:59:13  profilanswer
 

Pourquoi tu passes par un exists, ta jointure suffit amplement

Code :
  1. SELECT A.*
  2. FROM vues V, annonces A
  3. WHERE annonces.id_annonce = vues.id_annonce

n°1484672
Beegee
Posté le 30-11-2006 à 22:43:39  profilanswer
 

Il veut retourner les 30 premières annonces, or il peut y avoir plusieurs photos par annonce, d'où le passage (logique) par EXISTS.
 
SELECT *
FROM annonces
WHERE
EXISTS (SELECT *
        FROM vues
        WHERE vues.id_annonce = annonces.id_annonce)
LIMIT 0 , 30;

n°1484683
MagicBuzz
Posté le 30-11-2006 à 23:29:51  profilanswer
 

à la limite la requête d'anapajari marche si on colle un distinct, mais ce sera plus lent.

n°1484740
anapajari
s/travail/glanding on hfr/gs;
Posté le 01-12-2006 à 08:52:44  profilanswer
 

Beegee a écrit :

Il veut retourner les 30 premières annonces, or il peut y avoir plusieurs photos par annonce, d'où le passage (logique) par EXISTS.


Nan nan pas logique ....
 

MagicBuzz a écrit :

à la limite la requête d'anapajari marche si on colle un distinct, mais ce sera plus lent.


Pas vrai, ça dépend à la fois des sgbd et des index.  
Mais de toute façon vu c'est excatement la même requete que dans le exists ça peut pas être plus long  [:klem3i1]  
 

n°1484786
Beegee
Posté le 01-12-2006 à 10:14:17  profilanswer
 

Clair que ça dépend des index et du SGBD ... perso je trouve ça plus lisible avec le EXISTS (que de faire la jointure puis un DISTINCT).
 
Au passage, ça va plus ou moins retourner toujours les mêmes annonces ... faut faire un random si on veut des annonces au pif mais ayant des photos.

n°1484840
MagicBuzz
Posté le 01-12-2006 à 11:48:34  profilanswer
 

anapajari > pas vrai pour le coup du "ça dépends des index et toussa".
 
la seule chose dont va dépendre la vitesse d'un DISTINCT comparé à un EXISTS, c'est que le DISTINCT va prendre de plus en plus de temps (de façon plus ou moins exponentielle) quand le nombre de lignes va grandir, alors que le EXISTS va continuer à tourner avec la même vitesse (à peu de chose près, c'est plus évolution logarythmique).
 
Je rappelle quand même (une fois plus, y'en a, même parmis les habitués, genre anapajari, qui ont la tête dure) que le EXISTS ne fait que tester la validité d'une jointure. Il est de notoriété publique qu'une jointure ça ne consomme rien ou presque, même sur un SGBD merdique comme Access ou MySQL.
 
L'intérêt d'une jointure couplée à un LIMIT, si on ne spécifie rien d'autre (pas de distinct, group by, order by ou having) c'est que le SGBD ne va effectivement prendre que les 30 premières lignes. A partir du moment où on a un DISTINCT par exemple, le SGBD doit lire plus de lignes que demandé par le LIMIT, car il devra enlever les doublons. Ca peut rapidement devenir très lent.
 
En gros, la requête proposée par Beegee, et j'abonde dans son sens fait :
1 jointure
lecture des 30 premières lignes première lignes de la table principale
AUCUNE lecture des données dans la table liée
 
Le distinct, lui, pour fonctionner, doit comparer chaque tuple retourné avec les précédents tuples retournés. Il en découle qu'au fur et à mesure que le nombre de lignes évolue, ça devient catastrophique.
Mais surtout, la requête prônée à tord par Anapajari fait :
1 jointure
lecture de toutes les lignes de la table principale et de la table liée
recheche des 30 premiers tuples uniques parmis les champs sélectionnés
 
Bref, pas besoin de bencher pour voir que c'est plus lent qu'avec le EXISTS : à la base, le EXISTS fait moins de travail. :spamafote:


Message édité par MagicBuzz le 01-12-2006 à 11:51:44
n°1484887
anapajari
s/travail/glanding on hfr/gs;
Posté le 01-12-2006 à 12:41:16  profilanswer
 

I'm pas d'accord...
D'abord le "limit" comme tu dis est pas implémenté de la même façon sur tous les sgbd, d'ailleurs même la syntaxe n'est pas identique:

DB2   select * from table fetch first 10 rows only
Informix  select first 10 * from table
Microsoft SQL Server and Access  select top 10 * from table
MySQL and PostgreSQL  select * from table limit 10


Donc ta phrase:

Citation :

L'intérêt d'une jointure couplée à un LIMIT, si on ne spécifie rien d'autre (pas de distinct, group by, order by ou having) c'est que le SGBD ne va effectivement prendre que les 30 premières lignes.


est vrai dans le cas d'un limit mais pas d'un fetch first par exemple.


Message édité par anapajari le 01-12-2006 à 12:41:51
n°1484906
anapajari
s/travail/glanding on hfr/gs;
Posté le 01-12-2006 à 13:38:58  profilanswer
 

Tiens petit test fait sur DB2:

Code :
  1. select A.id from table A where exists ( select B.id from B where A.id = B.id)


db2explain puis show optimized query donne

Code :
  1. select distinct A.id from A inner join B on A.id = B.id
 

C'est trop fou ça  [:hahaguy]

 

Donc ouais c'est vrai j'ai la tête dure ...


Message édité par anapajari le 01-12-2006 à 13:39:51
n°1484950
Beegee
Posté le 01-12-2006 à 14:31:54  profilanswer
 

Refais la meme chose en recuperant plus de donnes de la table A pour voir :)

mood
Publicité
Posté le 01-12-2006 à 14:31:54  profilanswer
 

n°1485040
MagicBuzz
Posté le 01-12-2006 à 16:05:01  profilanswer
 

c clair que moi j'attends le résultat de l'une et l'autre avec un jeu de données important.
 
moi je ne crois pas un quart de seconde qu'un DISTINCT puisse être "optimized".
 
ça et le UNION (sans "ALL" ) ainsi que le IN, ce sont les trois instructions à éviter comme la peste.
n'importe quelle doc de n'importe quel SGBD le dit.
 
moi j'invente rien, et c'est 10 ans d'expérience qui parlent.

n°1485075
MagicBuzz
Posté le 01-12-2006 à 16:28:56  profilanswer
 

a noter aussi (j'avais pas fait gaffe) que tu récupère l'ID de la table A.
 
c'est cool, mais forcément, un DISTINCT sur une un PK, c'est pas vraiment pareil que sur un champ (même indexé).
 
refais-nous la requête avec un distinct sur un autre champ (non unique) de la table A...

n°1485078
MagicBuzz
Posté le 01-12-2006 à 16:30:30  profilanswer
 

en plus ton exemple est bancal, la FK de B vers A est aussi la PK de B... au lieu de faire une jointure de cardinalité 0,n, tu fais une cardinalité 0,1, donc le distinct est inutile (et certainement ignoré par l'optimiseur)

n°1485112
anapajari
s/travail/glanding on hfr/gs;
Posté le 01-12-2006 à 16:48:59  profilanswer
 

Ok the chiffres:
table dossiers: 277404 records
table finan: 537672
 
le explain et optimized query de

Code :
  1. select * from dossiers where exists ( select fin_iddos from finan where fin_iddos=dos_id)


donne

Code :
  1. select
  2. ...
  3. la liste des 60 champs
  4. ...
  5. from dossiers, finan where ( dos_id = fin_iddos)


Mieux les plans d'executions sont les suivants:
jointure:

Optimizer Plan:
 
          RETURN
          (   1)
            |
          HSJOIN
          (   2)
         /      \
  TBSCAN          IXSCAN
  (   3)          (   4)
    |            /      \
 Table:    Index:     Table:
 DB2INST1  DB2INST1   DB2INST1
 DOSSIERS  FIN_IDDOS  FINAN


exists:


Optimizer Plan:
 
          RETURN
          (   1)
            |
          HSJOIN
          (   2)
         /      \
  TBSCAN          IXSCAN
  (   3)          (   4)
    |            /      \
 Table:    Index:     Table:
 DB2INST1  DB2INST1   DB2INST1
 DOSSIERS  FIN_IDDOS  FINAN


 
Alors je suis a 600% d'accord pour le union et le in, mais pour le exists toujours pas [:dawa]

n°1485122
MagicBuzz
Posté le 01-12-2006 à 16:54:14  profilanswer
 

déjà, y'a pas la moitié des infos : par rapport à ta requête à toi ?
 
ensuite, ça donne quoi niveau résultat (temps d'exécution)
 
parceque le plan, c'est joli, mais parfois on a des surprises
 
sinon, à vue de nez, t'as juste l'air de nous sortir qu'au mieux, c'est équivalent... alors autant utiliser le EXISTS qui veut dire ce qu'il veut dire, plutôt qu'un DISTINCT et une jointure qui risque de foutre la merde le jour où on veut modifier la requête.

n°1485144
anapajari
s/travail/glanding on hfr/gs;
Posté le 01-12-2006 à 17:19:52  profilanswer
 

Entièrement d'accord avec le fait que le exists est plus clair à lire dans ce cas-ci.
Alors oui les résultats sont equivalents et voila le score:
exits:


* 272822 row(s) fetched, 5 row(s) output.

 

* Prepare Time is:       0,090023 seconds
* Execute Time is:       0,225449 seconds
* Fetch Time is:        17,107546 seconds
* Elapsed Time is:      17,423018 seconds (complete)

 

** The following warnings were issued:
** CLI warning in fetching next query result row:
(-99999): [IBM][CLI Driver] CLI0002W  Data truncated. SQLSTATE=01004

 

* Summary Table:

 

Type      Number      Repetitions Total Time (s) Min Time (s)   Max Time (s)   Arithmetic Mean Geometric Mean Row(s) Fetched Row(s) Output
--------- ----------- ----------- -------------- -------------- -------------- --------------- -------------- -------------- -------------
Statement           1           1      17,423018      17,423018      17,423018       17,423018      17,423018         272822             5

 

* Total Entries:              1
* Total Time:                17,423018 seconds
* Minimum Time:              17,423018 seconds
* Maximum Time:              17,423018 seconds
* Arithmetic Mean Time:      17,423018 seconds
* Geometric Mean Time:       17,423018 seconds
---------------------------------------------

  

jointure


* 537605 row(s) fetched, 5 row(s) output.

 

* Prepare Time is:       0,065094 seconds
* Execute Time is:       0,238727 seconds
* Fetch Time is:        16,685027 seconds
* Elapsed Time is:      16,988848 seconds (complete)

 

** The following warnings were issued:
** CLI warning in fetching next query result row:
(-99999): [IBM][CLI Driver] CLI0002W  Data truncated. SQLSTATE=01004

 

* Summary Table:

 

Type      Number      Repetitions Total Time (s) Min Time (s)   Max Time (s)   Arithmetic Mean Geometric Mean Row(s) Fetched Row(s) Output
--------- ----------- ----------- -------------- -------------- -------------- --------------- -------------- -------------- -------------
Statement           1           1      16,988848      16,988848      16,988848       16,988848      16,988848         537605             5

 

* Total Entries:              1
* Total Time:                16,988848 seconds
* Minimum Time:              16,988848 seconds
* Maximum Time:              16,988848 seconds
* Arithmetic Mean Time:      16,988848 seconds
* Geometric Mean Time:       16,988848 seconds
---------------------------------------------


[mode honnête]
Par contre j'ai également fait le test sur une autre table ou les indexs sont merdeux et dans cas là, le fetch de la jointure est en gros deux fois celui du exists :o
[/mode honnête]


Message édité par anapajari le 01-12-2006 à 17:20:22
n°1485147
MagicBuzz
Posté le 01-12-2006 à 17:30:35  profilanswer
 

:D

n°1485265
Beegee
Posté le 02-12-2006 à 00:06:29  profilanswer
 

Et puis vaut mieux lancer chaque requête 2 fois, ou vider le cache avant chaque requête ... parce que sinon la 2ème requête profite toujours de la mise en cache de certaines données dû au lancement de la 1ère requête :D

n°1485269
MagicBuzz
Posté le 02-12-2006 à 00:17:08  profilanswer
 

Bah ça, ça dépends du SGBD et de la charge mémoire par contre.
Sous Oracle par exemple, tu peux lancer une pure requête de merde qui va prendre 5 minutes, tu peux être sûr que si tu es seul sur le serveur et que tu redemandes plusieurs minutes plus tard,y va te sortir des temps à la con genre 2ms (c'est relou à souhait pour débuguer une requête qui est lente... t'es obligé de ruser à lui gavant le cache avec des requêtes bidons entre chaque test :sweat:)


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  Mysql : requete avec EXISTS

 

Sujets relatifs
[MySQL] Problème avec requête et condition IN[PHP/MySql] [Resolu merci !]Insertion de données temporaire.
[MySQL] Limiter la taille du processus mySQL[SQL] Besoin d'aide sur les attributs pour une requete
[SGBD/SQL] lenteur mysql/windowsRêquete d'un débutant
PHP / MYSQL ajout de % dans un champs BDDprobleme pour inserer une requete php dans du javascript
Pb requete MYSQL avec NOT EXISTS 
Plus de sujets relatifs à : Mysql : requete avec EXISTS


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR