Jointure avec un OR [Résolu] [SQL] - SQL/NoSQL - Programmation
Marsh Posté le 06-05-2009 à 16:30:20
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.
Marsh Posté le 06-05-2009 à 16:39:16
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
Marsh Posté le 06-05-2009 à 16:40:01
jmbianca a écrit :
|
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?
Marsh Posté le 06-05-2009 à 16:43:01
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?
Marsh Posté le 06-05-2009 à 16:45:20
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)
Marsh Posté le 06-05-2009 à 16:45:34
D'ailleurs c'est voulu le met_status=3 dans la jointure au lieu d'avoir une clause where?
Marsh Posté le 06-05-2009 à 16:47:26
@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
Marsh Posté le 06-05-2009 à 16:49:35
@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
Marsh Posté le 06-05-2009 à 16:50:05
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
Marsh Posté le 06-05-2009 à 16:52:10
(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...)
Marsh Posté le 06-05-2009 à 16:55:49
jmbianca a écrit :
|
une auto-jointure ?
Marsh Posté le 06-05-2009 à 16:56:50
Je me rends compte que mon exemple n'etait pas suffisant. En fait, je fais des regroupement style :
Code :
|
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
Marsh Posté le 06-05-2009 à 17:03:52
jmbianca a écrit : Je me rends compte que mon exemple n'etait pas suffisant. En fait, je fais des regroupement style :
|
Déjà ta jointure est pas super là, ça donnerait plutôt ça si je lis bien :
Code :
|
Marsh Posté le 06-05-2009 à 17:07:57
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)
Marsh Posté le 06-05-2009 à 17:08:57
...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...
Marsh Posté le 06-05-2009 à 17:10:36
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...
Marsh Posté le 06-05-2009 à 17:10:37
@skeye : un peu HS, mais comment tu fais pour faire la coloration syntaxique sur le SQL ?
Marsh Posté le 06-05-2009 à 17:11:29
jmbianca a écrit : @skeye : un peu HS, mais comment tu fais pour faire la coloration syntaxique sur le SQL ? |
|
Marsh Posté le 06-05-2009 à 17:11:56
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.
Marsh Posté le 06-05-2009 à 17:13:19
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
Marsh Posté le 06-05-2009 à 17:14:12
(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.... )
Marsh Posté le 06-05-2009 à 17:15:50
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). |
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)
Marsh Posté le 06-05-2009 à 17:17:46
@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)
Marsh Posté le 06-05-2009 à 17:21:01
@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...
Marsh Posté le 06-05-2009 à 17:24:50
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
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.
Marsh Posté le 06-05-2009 à 17:29:34
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...
Marsh Posté le 06-05-2009 à 17:31:09
jmbianca a écrit : ce qui serait interressant si les meetings se faisait avec un seul groupe |
euh, non.
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é...
Marsh Posté le 06-05-2009 à 17:34:57
Ta requête précédente deviendrait un truc de ce style :
Code :
|
...et là ça coule tout seul...
Marsh Posté le 06-05-2009 à 17:50:26
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
Marsh Posté le 06-05-2009 à 18:18:04
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 :
|
Marsh Posté le 07-05-2009 à 08:55:36
@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...
Marsh Posté le 06-05-2009 à 15:42:36
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 :
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 édité par jmbianca le 06-05-2009 à 17:50:57