使用多个条件连接加快MySql查询时间

时间:2015-04-18 19:30:06

标签: mysql sql left-join inner-join

有3个表,persontbl1,persontbl2(每个7500行)和日程表(~3000个活动日程表,即schedule.status = 0)。人员表包含与一对一关系相同的人的数据,两者之间的INNER连接不到一秒钟。并且时间表包含有关被访问人员的数据,而不是所有人都有时间表中的时间表。使用左连接查询需要大约45秒,这会导致各种问题。

SELECT persontbl1._CREATION_DATE, persontbl2._TOP_LEVEL_AURI, 
       persontbl2.RESP_CNIC, persontbl2.RESP_CNIC_NAME, 
       persontbl1.MOB_NUMBER1, persontbl1.MOB_NUMBER2, 
       schedule.id, schedule.call_datetime, schedule.enum_id,
       schedule.enum_change, schedule.status
FROM persontbl1
INNER JOIN persontbl2 ON (persontbl2._TOP_LEVEL_AURI = persontbl1._URI)
                      AND (AGR_CONTACT=1)
LEFT JOIN SCHEDULE ON (schedule.survey_id = persontbl1._URI)
                  AND (SCHEDULE.status=0)
                  AND (DATE(SCHEDULE.call_datetime) <= CURDATE())   
ORDER BY schedule.call_datetime IS NULL DESC, persontbl1._CREATION_DATE ASC

以下是查询说明:

enter image description here

日程表结构:

enter image description here

计划表索引:

enter image description here

如果需要任何进一步的信息,请告诉我。

感谢。

编辑:添加了完全限定的表名及其列。

2 个答案:

答案 0 :(得分:1)

你应该只替换这一行:

AND (DATE(SCHEDULE.call_datetime) <= CURDATE())

到这一个:

AND SCHEDULE.call_datetime <= '2015-04-18 00:00:00'

所以mysql不会为每条记录调用2个函数,但会使用静态常量'2015-04-18 00:00:00'

如果您的查询是:

,那么您可以尝试提高性能
SELECT persontbl1._CREATION_DATE, persontbl2._TOP_LEVEL_AURI, 
       persontbl2.RESP_CNIC, persontbl2.RESP_CNIC_NAME, 
       persontbl1.MOB_NUMBER1, persontbl1.MOB_NUMBER2, 
       schedule.id, schedule.call_datetime, schedule.enum_id,
       schedule.enum_change, schedule.status
FROM persontbl1
INNER JOIN persontbl2 ON (persontbl2._TOP_LEVEL_AURI = persontbl1._URI)
                      AND (AGR_CONTACT=1)
LEFT JOIN SCHEDULE ON (schedule.survey_id = persontbl1._URI)
                  AND (SCHEDULE.status=0)
                  AND (SCHEDULE.call_datetime <= '2015-02-01 00:00:00')   
ORDER BY schedule.call_datetime IS NULL DESC, persontbl1._CREATION_DATE ASC

编辑1 所以你说没有LEFT JOIN部分它足够快,所以你可以试试:

SELECT persontbl1._CREATION_DATE, persontbl2._TOP_LEVEL_AURI, 
       persontbl2.RESP_CNIC, persontbl2.RESP_CNIC_NAME, 
       persontbl1.MOB_NUMBER1, persontbl1.MOB_NUMBER2, 
       s.id, s.call_datetime, s.enum_id,
       s.enum_change, s.status
FROM persontbl1
INNER JOIN persontbl2 ON (persontbl2._TOP_LEVEL_AURI = persontbl1._URI)
                      AND (AGR_CONTACT=1)
LEFT JOIN 
  (SELECT *
   FROM SCHEDULE
   WHERE status=0
     AND call_datetime <= '2015-02-01 00:00:00'  
  ) s
ON s.survey_id = persontbl1._URI

ORDER BY s.call_datetime IS NULL DESC, persontbl1._CREATION_DATE ASC

答案 1 :(得分:0)

我猜AGR_CONTACT来自p1。这是您要优化的查询:

SELECT p1._CREATION_DATE, _TOP_LEVEL_AURI, RESP_CNIC, RESP_CNIC_NAME,
       MOB_NUMBER1, MOB_NUMBER2, 
       s.id, s.call_datetime, s.enum_id, s.enum_change, s.status
FROM persontbl1 p1 INNER JOIN
     persontbl2 p2
     ON (p2._TOP_LEVEL_AURI = p1._URI) AND (p1.AGR_CONTACT = 1) LEFT JOIN
     SCHEDULE s
     ON (s.survey_id = p1._URI) AND
     (s.status = 0) AND
     (DATE(s.call_datetime) <= CURDATE())   
ORDER BY s.call_datetime IS NULL DESC, p1._CREATION_DATE ASC;

此查询的最佳索引是:persontbl2(agr_contact)persontbl1(_TOP_LEVEL_AURI, _uri)schedule(survey_id, status, call_datime)

不建议在日期时间周围使用date()。通常,这会排除索引的使用。但是,在这种情况下,您有一个left join,所以它没有什么区别。该列无论如何都不用于过滤。 schedule上的索引仅用于涵盖on子句。

相关问题