2014-05-13 6 views
0

S'il vous plaît examiner la requête suivanteMySql compliquée joindre problème de performance

SELECT * FROM PC_SMS_OUTBOUND_MESSAGE AS OM 
JOIN MM_TEXTOUT_SERVICE AS TOS ON TOS.TEXTOUT_SERVICE_ID = OM.SERVICE_ID 
JOIN PC_SERVICE_NUMBER AS SN ON OM.TO_SERVICE_NUMBER_ID = SN.SERVICE_NUMBER_ID  
JOIN PC_SUBSCRIBER AS SUB ON SUB.SERVICE_NUMBER_ID = SN.SERVICE_NUMBER_ID 
JOIN MM_CONTACT CON ON CON.SUBSCRIBER_ID = SUB.SUBSCRIBER_ID 

--AND CON.MM_CLIENT_ID = 1 

AND OM.CLIENT_ID= 1 
AND OM.CREATED>='2013-05-08 11:47:53' AND OM.CREATED<='2014-05-08 11:47:53' 
ORDER BY OM.SMS_OUTBOUND_MESSAGE_ID DESC LIMIT 50 

Pour obtenir l'ensemble de données dont j'ai besoin je dois filtrer sur la (commentée) CONTACTS CLIENT_ID ainsi que les OUTBOUND_MESSAGES CLIENT_ID mais c'est ce qui change la performance de millisecondes à des dizaines de minutes.

plan d'exécution sans "ET CON.MM_CLIENT_ID = 1 ":

id select_type table type possible_keys key key_len ref rows filtered Extra 
1 SIMPLE OM index FK4E518EAA19F2EA2B,SERVICEID_IDX,CREATED_IDX,CLIENTID_IDX,CL_CR_ST_IDX,CL_CR_STYPE_ST_IDX,SID_TOSN_CL_CREATED_IDX PRIMARY 8 NULL 6741 3732.00 Using where 
1 SIMPLE SUB ref PRIMARY,FKA1845E3459A7AEF FKA1845E3459A7AEF 9 mmlive.OM.TO_SERVICE_NUMBER_ID 1 100.00 Using where 
1 SIMPLE SN eq_ref PRIMARY PRIMARY 8 mmlive.OM.TO_SERVICE_NUMBER_ID 1 100.00 Using where 
1 SIMPLE CON ref FK2BEC061CA525D30,SUB_CL_IDX FK2BEC061CA525D30 8 mmlive.SUB.SUBSCRIBER_ID 1 100.00 
1 SIMPLE TOS eq_ref PRIMARY,FKDB3DF298AB3EF4E2 PRIMARY 8 mmlive.OM.SERVICE_ID 1 100.00 

plan d'exécution avec" ET CON.MM_CLIENT_ID = 1":

id select_type table type possible_keys key key_len ref rows filtered Extra 
1 SIMPLE CON ref FK2BEC061CA525D30,FK2BEC06134399E2A,SUB_CL_IDX FK2BEC06134399E2A 8 const 18306 100.00 Using temporary; Using filesort 
1 SIMPLE SUB eq_ref PRIMARY,FKA1845E3459A7AEF PRIMARY 8 mmlive.CON.SUBSCRIBER_ID 1 100.00 
1 SIMPLE OM ref FK4E518EAA19F2EA2B,SERVICEID_IDX,CREATED_IDX,CLIENTID_IDX,CL_CR_ST_IDX,CL_CR_STYPE_ST_IDX,SID_TOSN_CL_CREATED_IDX FK4E518EAA19F2EA2B 9 mmlive.SUB.SERVICE_NUMBER_ID 3 100.00 Using where 
1 SIMPLE SN eq_ref PRIMARY PRIMARY 8 mmlive.SUB.SERVICE_NUMBER_ID 1 100.00 Using where 
1 SIMPLE TOS eq_ref PRIMARY,FKDB3DF298AB3EF4E2 PRIMARY 8 mmlive.OM.SERVICE_ID 1 100.00 

Toutes les suggestions sur la façon mettre en forme le ci-dessus pour le rendre un peu plus facile sur l'oeil serait bon.

Les champs ID sont des clés primaires. Il existe des index sur toutes les colonnes de jointure.

+0

Vous semblez manquer une clause 'WHERE' et la table' OM'.C'est l'un de ces cas où nous devons voir le résultat EXPLAIN et tous les index sur les tables incluses. –

+0

Je ne pense pas où est requis ici. ET semble fonctionner correctement sans cela quand je testerai. Compris sur le résultat EXPLAIN. Devra faire rouler la vraie requête pour cela. – dre

+0

Modifié pour afficher une requête réelle avec un plan d'exécution. – dre

Répondre

0

J'ai résolu l'énigme! Pour mon cas de toute façon, je vais partager.

Tout cela est venu à l'ordre de jointure changeant une fois que j'ai ajouté cette clause supplémentaire, que vous pouvez voir clairement dans le plan d'exécution. Lorsque la requête est rapide, les messages sortants sont en haut du plan, mais lorsqu'ils sont lents (après l'ajout de la clause), la table Contacts est en haut. Je pense que cela signifie que l'index des messages sortants ne peut plus être utilisé pour le tri qui cause le redouté;

"Using temporary; Using filesort" 

En ajoutant simplement STRAIGHT_JOIN mot-clé directement après la sélection que je pouvais forcer le plan d'exécution à se joindre à l'ordre désigné directement par la requête. Heureux pour quiconque ayant une connaissance plus intime de ce domaine de contredire tout ce qui précède en termes de ce qui se passe réellement, mais cela a vraiment fonctionné.

0

Vous pourriez être en mesure de résoudre ce problème en utilisant un sous-requête:

JOIN (SELECT C.* FROM CONTACTS C WHERE C.USER_ID = 1) ON C.SUBSCRIBER_ID = SUB.ID 

Cela matérialise les lignes correspondantes, ce qui pourrait avoir des effets en aval sur le plan de requête.

Si cela ne fonctionne pas, puis modifiez votre requête et ajoutez:

  • Les explain plans pour les deux requêtes.
  • Les index disponibles sur la table.

EDIT:

Pouvez-vous essayer de créer un index composite:

PC_SMS_OUTBOUND_MESSAGE(CLIENT_ID, CREATED, SERVICE_ID, TO_ SERVICE_ID, SMS_OUTBOUND_MESSAGE_ID); 

Cela peut changer à la fois la requête prévoit de commencer sur la table OM avec le filtrage approprié, ce qui, espérons les résultats stables et bien.

+0

Avait essayé, n'a pas fonctionné .. et j'ai vraiment pensé que ce serait! :(Je suppose que c'est parce que CONTACTS a des millions d'enregistrements. \ R \ n \ r \ nTexte nécessitera l'utilisation de la requête "monde réel" – dre

+0

@dre ... Avez-vous un index sur 'CONTACTS (USER_ID)'? –

+0

Oui, j'ai cet index – dre