SELECT DISTINCT journey.id, line.name AS line, getDestination(pattern.section) AS destination, TIME_FORMAT(ADDTIME(journey.departure, SEC_TO_TIME(SUM(pl2.time))), '%H:%i') AS departure, operator.code AS operator, bus.registration
FROM journey
INNER JOIN journey_day ON journey_day.journey = journey.id
INNER JOIN service ON service.id = journey.service
INNER JOIN operator ON operator.id = service.operator
INNER JOIN line ON line.service = service.id
INNER JOIN pattern ON pattern.id = journey.pattern
INNER JOIN pattern_link pl ON pl.section = pattern.section AND pl.from_stop = :stop
INNER JOIN pattern_link pl2 ON pl2.section = pattern.section AND pl2.sequence < pl.sequence
LEFT JOIN findmybus.bus ON bus.journey_id = journey.id
WHERE journey_day.day = :day AND CURDATE() BETWEEN service.date_start and service.date_end AND operator.id = :operator
GROUP BY journey.id, journey.departure
HAVING (TIME_TO_SEC(journey.departure) + SUM(pl2.time)) < 86400
以下是查询前面的EXPLAIN
语句的结果:
为什么这个查询这么慢?我已经为ON
子句中连接的所有列添加了索引。似乎它们并非全部被使用,为什么会这样呢?
查询结果:
答案 0 :(得分:0)
关于使用索引:当您访问一小部分数据时,这会付费。通过查看您的查询,我会猜到dbms以journey_day表开头。该表中可能有数千天,因此将其限制在某一特定日期应该会从表中选择一小部分。
但是,那将是多少次旅行,或者更准确地说:旅程表的相关百分比是多少? dbms必须估计这个以决定是否支持索引使用。这适用于每一张桌子。
你可以尝试通过将journey_day标准移动到exists子句来加快速度,但说实话,我不希望这会有多大帮助。正如您已经在做的那样,只需加入MySql通常是最好的。无论如何,为什么不试试呢?
SELECT DISTINCT
journey.id,
GROUP_CONCAT(line.name) AS lines,
getDestination(pattern.section) AS destination,
TIME_FORMAT(ADDTIME(journey.departure, SEC_TO_TIME(SUM(pl2.time))), '%H:%i') AS departure,
operator.code AS operator,
GROUP_CONCAT(bus.registration) as registrations
FROM journey
INNER JOIN service ON service.id = journey.service AND CURDATE() BETWEEN service.date_start and service.date_end
INNER JOIN operator ON operator.id = service.operator AND operator.id = :operator
INNER JOIN line ON line.service = service.id
INNER JOIN pattern ON pattern.id = journey.pattern
INNER JOIN pattern_link pl ON pl.section = pattern.section AND pl.from_stop = :stop
INNER JOIN pattern_link pl2 ON pl2.section = pattern.section AND pl2.sequence < pl.sequence
LEFT JOIN findmybus.bus ON bus.journey_id = journey.id
WHERE EXISTS
(
SELECT *
FROM journey_day
WHERE journey_day.journey = journey.id
AND journey_day.day = :day
)
GROUP BY journey.id
HAVING (TIME_TO_SEC(journey.departure) + SUM(pl2.time)) < 86400;