MySql复杂的连接性能问题

时间:2014-05-13 11:30:44

标签: mysql query-performance composite-index

请考虑以下查询

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

要获取我需要的数据集,我需要过滤掉(已注释掉的)CONTACTS client_id以及OUTBOUND_MESSAGES client_id,但这会将性能从毫秒改为数十分钟。

没有“ AND 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  

执行计划“ AND 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  

关于如何格式化上述内容以使其更容易在眼睛上的任何建议都会很好。

ID字段是主键。 所有连接列都有索引。

2 个答案:

答案 0 :(得分:0)

您可以使用子查询解决此问题:

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

这将实现匹配的行,这些行可能对查询计划产生下游影响。

如果这不起作用,请编辑您的查询并添加:

  • 两个查询的explain计划。
  • 表格中提供的索引。

编辑:

您可以尝试创建综合索引:

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

这可能会改变两个查询计划,以便在OM表上启动并进行适当的过滤,希望结果稳定且良好。

答案 1 :(得分:0)

我已经解开了这个谜语!无论如何,对于我的情况,我会分享。

这一切都归结为连接顺序的更改,一旦我添加了额外的子句,您可以在执行计划中清楚地看到。当查询速度很快时,出站消息位于计划的顶部,但是当缓慢(添加子句后)时,“联系人”表位于顶部。 我认为这意味着出站消息索引不能再用于导致可怕的排序;

 "Using temporary; Using filesort"

只需在选择后直接添加 STRAIGHT_JOIN 关键字即可强制执行计划按查询直接表示的顺序加入。 对于对这个领域有更深入了解的人来说,在实际发生的事情上与上述任何内容相矛盾,但是它确实很有效。