2012-10-27 5 views
1

J'ai une situation MySQL impliquant de nombreuses tables et une jointure à gauche et j'ai du mal à m'en sortir!Résolution du problème de jointure à gauche avec plusieurs tables

Je vais essayer de le simplifier étape par étape.

La tâche principale que j'essaie de faire est de joindre deux tables. La première table contient des éléments et la seconde contient des actions effectuées sur des éléments. J'ai besoin chaque ligne de la table des éléments à sortir (même si aucune action n'a été effectuée sur eux) si une jointure gauche semble être la solution:

select item.ID, count(action.ID) as cnt 
from item 
left join action on action.itemID=item.ID 
group by ID 

La prochaine étape est que je dois réellement compter que certain type des articles. Comme je n'ai pas besoin des autres types, je les filtre avec une clause where.

select item.ID, count(action.ID) as cnt 
from item 
left join action on action.itemID=item.ID 
where item.type=3 
group by ID 

Maintenant, les choses deviennent un peu plus compliquées. J'ai également besoin de filtrer certains éléments en utilisant une autre table (info). Là, je n'étais pas sûr de savoir comment faire ça. Mais une simple jointure et où clause l'a fait.

select item.ID, count(action.ID) as cnt 
from (item, info) 
left join action on action.itemID=item.ID 
where item.type=3 and info.itemID=itemID and info.fr is not null 
group by ID 

Jusqu'ici tout va bien. Ma requête fonctionne et la performance est comme prévu. Maintenant, la dernière chose que je dois faire est de filtrer certaines actions (ne pas les compter) basées sur une autre table (sous-action). C'est là que les choses deviennent vraiment lentes et me déroutent. J'ai essayé ceci:

select item.ID, count(action.ID) as cnt 
from (item, info) 
left join (
      action join subaction on subaction.actionID=action.ID and subaction.type=6 
     ) on action.itemID=item.ID 
where item.type=3 and info.itemID=itemID and info.fr is not null 
group by ID 

À ce stade, la requête ralentit soudainement de plus de 1000 fois. Je fais évidemment quelque chose de mal!

J'ai essayé une simple requête qui fait presque ce dont j'ai besoin. Le seul problème est que cela ne comprend pas les éléments qui doivent correspondre à des actions. Mais j'ai besoin d'eux aussi.

select item.ID, count(action.ID) as cnt 
from item, info, action, subaction 
where item.type=3 and info.itemID=itemID and info.fr is not null and 
     action.itemID=item.ID subaction.actionID=action.ID and subaction.type=6 
group by ID 

Quelqu'un a une suggestion sur la façon de résoudre un tel problème? Existe-t-il un moyen standard de faire cela? Merci beaucoup !

EDIT

En fait, cette dernière requête que je soumettais est presque ce que je dois: il ne comprend pas les sous-requêtes, est vraiment performant, permet une utilisation optimale de mes index, est facile à lire, etc.

select item.ID, count(action.ID) as cnt 
from item, info, action, subaction 
where item.type=3 and info.itemID=itemID and info.fr is not null and 
     action.itemID=item.ID subaction.actionID=action.ID and subaction.type=6 
group by ID 

la seule petite chose qui ne ne comprend pas fonctionne pas est que lorsque le nombre est item.ID (action.ID) est 0.

Je suppose que ma question est vraiment comment dois-je modifier légèrement ci-dessus que ry pour qu'il renvoie également item.IDs lorsque count (action.ID) est 0. D'après ce que je vois, cela ne devrait pas changer les performances et l'utilisation de l'index. Il suffit d'inclure ces éléments supplémentaires avec 0 comme nombre.

+1

Avez-vous essayé 'EXPLAIN'ing la requête? –

Répondre

1

Essayez rejoint comme ci-dessous (en essayant d'appliquer la condition de filtre avant de rejoindre):

 SELECT item.ID, count(action.ID) as cnt 
     FROM item JOIN info 
      ON (item.type=3 AND info.fr is not null AND info.itemID=item.itemID) 
      LEFT JOIN action 
      ON (action.itemID=item.ID) 
      JOIN subaction 
      ON (subaction.actionID=action.ID and subaction.type=6) 
     GROUP by item.ID; 

EDIT:

 SELECT item.ID, count(action.ID) as cnt 
     FROM item JOIN info 
      ON (item.type=3 AND info.fr is not null AND info.itemID=item.itemID) 
      LEFT JOIN 
      (select a.* FROM action 
       JOIN subaction 
       ON (subaction.actionID=action.ID and subaction.type=6)) AS act 
      ON (act.itemID=item.ID) 
     GROUP by item.ID; 
+0

Le problème avec cela est que le dernier JOIN me fait perdre des éléments pour lesquels aucune action n'existe.En d'autres termes, le dernier JOIN annule les effets du LEFT JOIN. –

+0

Et si je fais aussi la dernière REJOIGNEZ UNE GAUCHE, j'obtiens les bons résultats mais les performances baissent drastiquement. –

+0

@GillesjrBisson Ajout d'une autre requête dans la réponse. Pouvez-vous s'il vous plaît essayer et laissez-moi savoir si cela aide? –

Questions connexes