使用多个条件连接加快 MySql 查询时间
Speed up MySql query time with multiple conditional joins
有 3 个 tables,persontbl1,persontbl2(每行 7500 行)和时间表(约 3000 个活动时间表,即 schedule.status = 0)。 Person tables 包含与一对一关系相同的人的数据,两者之间的 INNER join 需要不到一秒钟的时间。时间表 table 包含有关要采访的人的数据,并非所有人都有时间表 table。使用 Left join 查询立即需要大约 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
查询说明如下:
时间表Table结构:
计划 Table 索引:
如果需要任何进一步的信息,请告诉我。
谢谢。
编辑:添加了完全限定的 table 名称及其列。
我猜 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
子句。
你应该只替换这一行:
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
有 3 个 tables,persontbl1,persontbl2(每行 7500 行)和时间表(约 3000 个活动时间表,即 schedule.status = 0)。 Person tables 包含与一对一关系相同的人的数据,两者之间的 INNER join 需要不到一秒钟的时间。时间表 table 包含有关要采访的人的数据,并非所有人都有时间表 table。使用 Left join 查询立即需要大约 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
查询说明如下:
时间表Table结构:
计划 Table 索引:
如果需要任何进一步的信息,请告诉我。
谢谢。
编辑:添加了完全限定的 table 名称及其列。
我猜 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
子句。
你应该只替换这一行:
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