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

  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  [SQL] Jointure avec un OR [Résolu]

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[SQL] Jointure avec un OR [Résolu]

n°1881450
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 15:42:36  profilanswer
 

Bonjour,
 
J'ai un pb plutot complexe sur une requete, si qq a une solution :  
Pour faire simple, 2 tables :  
GROUPS
- grp_id (int) primary
- grp_name (varchar)
 
et
MEETING
- met_id (int) primary
- grp1 (int)
- grp2 (int)
- datemeeting (date)
- met_status (int) index
+ des index sur grp1, grp2, et grp1+grp2
 
Bref en gros, c'est une structure qui permet de loguer des rdv entre 2 groupes. Dans la table meeting, chaque grp1 et grp2 sont des clé etrangere vers grp_id de la table groups.
Et du coup, j'ai des requetes qui sont de la sorte :  
 

Code :
  1. SELECT g.grp_id, g.grp_name, m.datemeeting
  2. FROM groups g
  3. INNER JOIN meeting m ON (g.grp_id = m.grp1 OR g.grp_id = m.grp2) AND m.met_status = 3


 
Le probleme est que c'est pas tres optimisé du coup, et ca rame parfois (la table meeting fait dans les 20000 reg, la table groups dans les 5000)
 
Je voulais savoir comment optimiser/modifier ma jointure avec un OR
 
Merci d'avance
 
PS : Evidemment, les vrais structures sont plus complexe, mais je pense que pour l'exemple c'est suffisant
 
Edit: y'aurais bien la solution de faire un UNION avec 2 fois presque la meme requete, mais je suis pas sur que ca soit vraiment mieux, ni tres propre meme...

Message cité 2 fois
Message édité par jmbianca le 06-05-2009 à 17:50:57
mood
Publicité
Posté le 06-05-2009 à 15:42:36  profilanswer
 

n°1881484
olivthill
Posté le 06-05-2009 à 16:30:20  profilanswer
 

La requête est obligée de lire tous les enregistrements de la MEETING pour trouver le grp1 ou le grp2 qui puisse être relié à un groupe. Il n'est pas étonnant que cela prenne beaucoup de temps. Changer la requête ne vas pas donner d'amélioration si la jointure reste sur ces champs-là.
 
La solution consite à créer un index secondaire sur meeting.grp1 et d'un autre index secondaire sur meeting.grp2. La création d'un index est facile à faire. Au besoin, demander à un DBA de le faire. L'accelération sera impressionnante.


Message édité par olivthill le 06-05-2009 à 16:31:03
n°1881491
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 16:39:16  profilanswer
 

Merci pour ta réponse, mais comme je l'ai mis dans la description de la table Meeting, il y a deja des index secondaires :  
- sur grp1
- sur grp2
- sur grp1 + grp2
Mais la requete met presque 20 secondes a s'executer.
Pour info, c'est sur mySQL, des fois qu'il y ai des optimisations propre a ce SGBD qui soit applicable

n°1881492
skeye
Posté le 06-05-2009 à 16:40:01  profilanswer
 

jmbianca a écrit :


Code :
  1. SELECT g.grp_id, g.grp_name, m.datemeeting
  2. FROM groups g
  3. INNER JOIN meeting m ON (g.grp_id = m.grp1 OR g.grp_id = m.grp2) AND m.met_status = 3



 
Je vais a priori dire une connerie, mais quel est l'intérêt de mettre les deux groupes d'un même meeting dans 2 lignes de résultat différentes? :??:


---------------
Can't buy what I want because it's free -
n°1881494
skeye
Posté le 06-05-2009 à 16:43:01  profilanswer
 

La question derrière c'est : est-ce que tu ne pourrais pas tout simplement sélectionner tout le contenu de ta table meeting avec met_status=3 et faire le traitement dans le langage qui récupère le résultat derrière?


---------------
Can't buy what I want because it's free -
n°1881496
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 16:45:20  profilanswer
 

c'est pas une connerie, mais disons que pour les requetes reellement utilisés sur le site, ca a un sens. En gros, ca permet de sortir tous les groupes present a un evenement, qu'ils y ait participé en tant que grp1 ou grp2 (grp1 et grp2 n'ayant pas exactement la meme signification sur le site)

n°1881497
skeye
Posté le 06-05-2009 à 16:45:34  profilanswer
 

D'ailleurs c'est voulu le met_status=3 dans la jointure au lieu d'avoir une clause where?


---------------
Can't buy what I want because it's free -
n°1881498
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 16:47:26  profilanswer
 

@skeye : non parce que typiquement, j'utilise ce genre de requete pour faire des regroupements sur les autres champs. Et c'est quand meme plus rapide en SQL qu'en PHP

n°1881500
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 16:49:35  profilanswer
 

@skeye: le met_status=3 dans la jointure au lieu d'avoir une clause where est volontaire ouais. Ca permet de mettre toutes les clauses qui concernent une table au meme endroit. C'est plus propre et ca permet de mettre rapidement en commentaire une table quand on veux faire des tests. Du coup je me sert du WHERE que pour la table principale

n°1881501
skeye
Posté le 06-05-2009 à 16:50:05  profilanswer
 

jmbianca a écrit :

ca permet de sortir tous les groupes present a un evenement, qu'ils y ait participé en tant que grp1 ou grp2 (grp1 et grp2 n'ayant pas exactement la meme signification sur le site)


Justement, ta requête ne fait pas la différence...et tu répètes la date systématiquement...bref.
Par curiosité, niveau timing ça donne quoi comme différence ta requête par rapport à
 
SELECT m.*, g1.grp_name, g2.grp_name
FROM meeting
        JOIN group g1 ON (g1.grp_id = m.grp1)
        JOIN group g2 ON (g2.grp_id = m.grp2)  
WHERE m.met_status = 3
 
:??:


---------------
Can't buy what I want because it's free -
mood
Publicité
Posté le 06-05-2009 à 16:50:05  profilanswer
 

n°1881507
skeye
Posté le 06-05-2009 à 16:52:10  profilanswer
 

(sachant que récupérer le résultat de ma requête pour en faire la même chose en php qu'avec la tienne est trivial...)


Message édité par skeye le 06-05-2009 à 16:52:19

---------------
Can't buy what I want because it's free -
n°1881509
Harkonnen
Modérateur
Un modo pour les bannir tous
Posté le 06-05-2009 à 16:55:49  profilanswer
 

jmbianca a écrit :


Je voulais savoir comment optimiser/modifier ma jointure avec un OR


une auto-jointure ?
[:grilled]


Message édité par Harkonnen le 06-05-2009 à 16:56:15

---------------
J'ai un string dans l'array (Paris Hilton)
n°1881510
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 16:56:50  profilanswer
 

Je me rends compte que mon exemple n'etait pas suffisant. En fait, je fais des regroupement style :  
 

Code :
  1. SELECT g.grp_id, g.grp_name,
  2. SUM(CASE WHEN g.grp_id != m.sender_grp_id THEN 1 ELSE 0 END) AS nb_rdv_ask,
  3. SUM(CASE WHEN m.mas_status = 1 THEN 1 ELSE 0 END) AS nb_rdv_ok
  4. FROM groups g
  5. LEFT JOIN meeting m ON m.con_id = 8 AND (g.grp_id = m.grp1 OR g.grp_id = m.grp2)
  6. WHERE g.con_id = 8 AND g.grp_valid = 1
  7. GROUP BY g.grp_id, g.grp_name


 
Ce que je ne peux pas faire avec ta solution, qui va me renvoyer trop de resultats dans les SUM
PS : il y a des champs en plus qui n'etaient pas dans mon exemple simplifié, mais ca devrait pas changer grand chose

n°1881515
skeye
Posté le 06-05-2009 à 17:03:52  profilanswer
 

jmbianca a écrit :

Je me rends compte que mon exemple n'etait pas suffisant. En fait, je fais des regroupement style :  
 

Code :
  1. SELECT g.grp_id, g.grp_name,
  2. SUM(CASE WHEN g.grp_id != m.sender_grp_id THEN 1 ELSE 0 END) AS nb_rdv_ask,
  3. SUM(CASE WHEN m.mas_status = 1 THEN 1 ELSE 0 END) AS nb_rdv_ok
  4. FROM groups g
  5. LEFT JOIN meeting m ON m.con_id = 8 AND (g.grp_id = m.grp1 OR g.grp_id = m.grp2)
  6. WHERE g.con_id = 8 AND g.grp_valid = 1
  7. GROUP BY g.grp_id, g.grp_name



 
Déjà ta jointure est pas super là, ça donnerait plutôt ça si je lis bien :
 

Code :
  1. SELECT g.grp_id, g.grp_name,
  2. SUM(CASE WHEN g.grp_id != m.sender_grp_id THEN 1 ELSE 0 END) AS nb_rdv_ask,
  3. SUM(CASE WHEN m.mas_status = 1 THEN 1 ELSE 0 END) AS nb_rdv_ok
  4. FROM groups g
  5. LEFT JOIN meeting m ON (m.con_id = g.con_id AND (g.grp_id = m.grp1 OR g.grp_id = m.grp2) )
  6. WHERE g.con_id = 8
  7. AND g.grp_valid = 1
  8. GROUP BY g.grp_id, g.grp_name


---------------
Can't buy what I want because it's free -
n°1881517
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 17:07:57  profilanswer
 

certes, sauf que j'ai volontairement pas fait de jointure sur m.con_id = g.con_id pour lui laisser la possibilité d'utiliser les index sur grp1/grp2, ce qui m'interresse plus en terme de perfs (con_id seul renvoie trop de lignes)

n°1881519
skeye
Posté le 06-05-2009 à 17:08:57  profilanswer
 

...bon puis là s'il s'agit de faire du group by là-dessus je me ferais pas chier et je ferais ça sur l'union des deux cas et basta...[:joce]


---------------
Can't buy what I want because it's free -
n°1881520
skeye
Posté le 06-05-2009 à 17:10:36  profilanswer
 

jmbianca a écrit :

certes, sauf que j'ai volontairement pas fait de jointure sur m.con_id = g.con_id pour lui laisser la possibilité d'utiliser les index sur grp1/grp2, ce qui m'interresse plus en terme de perfs (con_id seul renvoie trop de lignes)


 
D'après le nom de ce champ c'est une clé étrangère, avoir un index dessus dans tes deux tables ne me parait pas délirant...et de toute manière je vois pas pourquoi il utiliserait pas les index sur grp1/2 dans ma version...


---------------
Can't buy what I want because it's free -
n°1881521
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 17:10:37  profilanswer
 

@skeye : un peu HS, mais comment tu fais pour faire la coloration syntaxique sur le SQL ?

n°1881524
skeye
Posté le 06-05-2009 à 17:11:29  profilanswer
 

jmbianca a écrit :

@skeye : un peu HS, mais comment tu fais pour faire la coloration syntaxique sur le SQL ?


 


[code=sql]
select ...
[/code]


---------------
Can't buy what I want because it's free -
n°1881525
casimimir
Posté le 06-05-2009 à 17:11:56  profilanswer
 

de toute facon soit tu fais un index composite, soit deux index, un sur grp1 et un sur grp2 et tu mets 2 left join du coup et tu rajoutes le m1.meeting_id = m2.meeting_id dans ton 2ème join.

n°1881526
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 17:13:19  profilanswer
 

y'a bien un index sur con_id dans mes 2 tables, mais encore une fois, c'est pas assez interressant en terme de perf (d'ailleurs mon ex. fait que c'est cet index qu'il utilise, et qui me fait des requetes de 20 secondes).
Et il utilise pas les index sur grp1/grp2 justement parce que c'est un OR. C'est tout le sujet de mon post au départ

n°1881527
skeye
Posté le 06-05-2009 à 17:14:12  profilanswer
 

(puis sinon on revient à la solution du calcul en php après coup, c'est quand même pas bien compliqué et ça doit pas être si lourd que ça de faire quelques centaines de 1+1+0+1+1+0.... :D)


Message édité par skeye le 06-05-2009 à 17:14:37

---------------
Can't buy what I want because it's free -
n°1881528
skeye
Posté le 06-05-2009 à 17:15:50  profilanswer
 

jmbianca a écrit :

y'a bien un index sur con_id dans mes 2 tables, mais encore une fois, c'est pas assez interressant en terme de perf (d'ailleurs mon ex. fait que c'est cet index qu'il utilise, et qui me fait des requetes de 20 secondes).
Et il utilise pas les index sur grp1/grp2 justement parce que c'est un OR. C'est tout le sujet de mon post au départ


Bataille pas dans ce cas, soit tu sépares les deux cas et tu regroupes en php (pas bien compliqué), soit tu te bases sur ma première requête et tu fais les sommes en php (probablement plus lourd...à tester)


Message édité par skeye le 06-05-2009 à 17:16:01

---------------
Can't buy what I want because it's free -
n°1881530
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 17:17:46  profilanswer
 

@casimir: si je fait 2 left join sur meeting et que je rajoute m1.met_id = m2.met_id, je vois pas l'interet... (ou alors j'ai loupé un truc)

n°1881536
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 17:21:01  profilanswer
 

@skeye : ta 1ere solution revient a faire un UNION, mais bon, je vais voir si j'y gagne en perfs, ca vaudra le coup, meme si c'est pas super propre...

n°1881543
skeye
Posté le 06-05-2009 à 17:24:50  profilanswer
 

jmbianca a écrit :

@skeye : ta 1ere solution revient a faire un UNION, mais bon, je vais voir si j'y gagne en perfs, ca vaudra le coup, meme si c'est pas super propre...


C'est ta structure de tables qui est pas propre, amha :D
Si tu avais une tablemeeting (met_id, datemeeting, met_status, sender_grp_id, mas_status, ...) et une autre meeting_group(grp_id, met_id) tu aurais pas tous ces problèmes. :D


Message édité par skeye le 06-05-2009 à 17:24:56

---------------
Can't buy what I want because it's free -
n°1881555
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 17:29:34  profilanswer
 

ce qui serait interressant si les meetings se faisait avec un seul groupe... mais dans le cas présent il y a 2 groupes dans chaque meeting, et il n'ont pas tout a fait le meme role suivant qu'ils sont dans grp1 ou grp2 (ce qui peut changer d'un meeting a l'autre). Je pourrais egalement transposer cette info dans ta table meeting_group, mais ca ne ferait que deplacer le pb en rajoutant une table X 2 dans toutes les requetes...

n°1881558
skeye
Posté le 06-05-2009 à 17:31:09  profilanswer
 

jmbianca a écrit :

ce qui serait interressant si les meetings se faisait avec un seul groupe


euh, non. :D
Le but du jeu c'est justement d'avoir plusieurs lignes dans cette table pour chaque meeting. Et cadeau bonux, tu peux même envisager d'ajouter un flag "role_groupe" dans cette table et c'est gagné...[:dawa]


---------------
Can't buy what I want because it's free -
n°1881564
skeye
Posté le 06-05-2009 à 17:34:57  profilanswer
 

Ta requête précédente deviendrait un truc de ce style :
 

Code :
  1. SELECT g.grp_id, g.grp_name,
  2. SUM(CASE WHEN g.grp_id != m.sender_grp_id THEN 1 ELSE 0 END) AS nb_rdv_ask,
  3. SUM(CASE WHEN m.mas_status = 1 THEN 1 ELSE 0 END) AS nb_rdv_ok
  4. FROM groups g
  5.    LEFT JOIN meeting_group mg ON (mg.con_id = g.con_id AND mg.grp_id = g.grp_id)
  6.    LEFT JOIN meeting m ON (m.met_id = mg.met_id)
  7. WHERE g.con_id = 8
  8. AND g.grp_valid = 1
  9. GROUP BY g.grp_id, g.grp_name


 
...et là ça coule tout seul...


---------------
Can't buy what I want because it's free -
n°1881572
jmbianca
https://mykonfig.com/
Posté le 06-05-2009 à 17:50:26  profilanswer
 

Yep, mais je me vois pas changer les 10zaines de requetes du site qui vont taper dans meeting pour ca. Mon but au départ etait de trouver une "astuce" pour résoudre la jointure avec le OR.
Enfin bref, j'ai fait la modif avec le UNION, c'est bcp mieux, et je vais rester la dessus, meme si c'est pas le plus "propre".
Merci a tous pour le coup de main

n°1881581
casimimir
Posté le 06-05-2009 à 18:18:04  profilanswer
 

jmbianca a écrit :

@casimir: si je fait 2 left join sur meeting et que je rajoute m1.met_id = m2.met_id, je vois pas l'interet... (ou alors j'ai loupé un truc)


 
tu es obligé de joiner ton meeting 1 avec meeting 2 sinon tu va faire un cross entre tres meetings.
 
ca donnerait ca mais le post part un peu dans tous les sens sans trop tout tester avant de rejeter le solution alors j'ai un peu de mal.
 
pour les index composite tu as vérifié le plan d'exécution? et si tu remplaces le or par un in?
 

Code :
  1. SELECT g.grp_id, g.grp_name,
  2. SUM(CASE WHEN g.grp_id NOT IN (m.sender_grp_id,m2.sender_grp_id) THEN 1 ELSE 0 END) AS nb_rdv_ask,
  3. SUM(CASE WHEN m.mas_status = 1 THEN 1 ELSE 0 END) AS nb_rdv_ok
  4. FROM groups g
  5. LEFT JOIN meeting m ON (m.con_id = g.con_id AND g.grp_id = m.grp1 )
  6. LEFT JOIN meeting m2 ON (m.con_id = g.con_id AND g.grp_id = m.grp2 AND m.meet_id = m2.meet_id)
  7. WHERE g.con_id = 8
  8. AND g.grp_valid = 1
  9. GROUP BY g.grp_id, g.grp_name


n°1881682
jmbianca
https://mykonfig.com/
Posté le 07-05-2009 à 08:55:36  profilanswer
 

@casimimir : merci pour tes propositions. Je vais essayer de tester ca aujourd'hui, mais comme je passe la journée en reunion, ca va pas etre facile...

mood
Publicité
Posté le   profilanswer
 


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

  [SQL] Jointure avec un OR [Résolu]

 

Sujets relatifs
[RESOLU] __call et les tableaux[SQL] Demande d'informations sur des requetes à créer
[SQL] Indiquer ou pas la présence de clé étrangère[SQL] Problème création BDD SQL
[SQL] Requêtes SQL, faux ou correct ?Afficher le resultat d'une requête SQL (VBA access)
[Résolu] dictionnaire avec un arbre binaire[SQL] Etablir un MCD des relations d'une base relationnelle[HELP]
[RESOLU] Probleme Application FileDialog[RESOLU]HTML - includes et charset
Plus de sujets relatifs à : [SQL] Jointure avec un OR [Résolu]


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