到目前为止,我已阅读有关我的问题的this和this链接,但无法完全理解这里发生了什么。这是查询:
explain SELECT
b.fk_gds_busline_commission,
COUNT(1)
FROM dw.ft_booking b
INNER JOIN dw.dm_date d ON b.fk_date_booking = d.sk_date
LEFT JOIN dw.dm_gds_busline_commission bl ON bl.sk_gds_busline_commission = b.fk_gds_busline_commission
LEFT JOIN dw.dm_routes r ON r.sk_route = b.fk_route
WHERE d.date >= '2018-01-01'
GROUP BY fk_gds_busline_commission
ORDER BY COUNT(1) DESC;
表格信息:
ft_booking - > 10M行
dm_gds_busline_commission - > 500行
dm_date - > 10k行
dm_routes - > 200k行
上面的查询结果为:
这里有两个主要问题,虽然我只对一个感兴趣。第一个是未使用指示的可能密钥(与其名称所建议的相应列相关)。关于这一点,这里有很多关于SO的讨论,原因很可能与未更新的表统计有关,等等。我能解决这个问题。在这种情况下,我尝试使用FORCE INDEX。
explain SELECT
b.fk_gds_busline_commission,
COUNT(1)
FROM dw.ft_booking b FORCE INDEX (fk_date_booking_idx)
LEFT JOIN dw.dm_gds_busline_commission bl ON bl.sk_gds_busline_commission = b.fk_gds_busline_commission
INNER JOIN dw.dm_date d ON b.fk_date_booking = d.sk_date
LEFT JOIN dw.dm_routes r ON r.sk_route = b.fk_route
WHERE d.date >= '2018-01-01'
GROUP BY fk_gds_busline_commission
ORDER BY COUNT(1) DESC;
这导致了与以前完全相同的结果。但是,我注意到,如果删除dm_gds_busline_commission或dm_routes表,结果会发生显着变化。选择顺序被更改,mysql选择使用索引(除非我省略FORCE INDEX子句 - 在这种情况下,只更改SELECT顺序)。然后,例如,
explain SELECT
b.fk_gds_busline_commission,
COUNT(1)
FROM dw.ft_booking b FORCE INDEX (fk_date_booking_idx)
INNER JOIN dw.dm_date d ON b.fk_date_booking = d.sk_date
LEFT JOIN dw.dm_routes r ON r.sk_route = b.fk_route
WHERE d.date >= '2018-01-01'
GROUP BY fk_gds_busline_commission
ORDER BY COUNT(1) DESC;
结果是
当我从查询中删除dm_routes表时会发生等效。
为了获取我需要加入的所有表,我必须删除连接的一个表,然后将此选择查询作为子查询,然后将缺少的表连接到已经聚合的结果组。这意味着,我已经执行了两个变通办法(使用FORCE INDEX,然后创建子查询)以绕过MySQL查询优化器失败。
比较结果,使用我的解决方法,查询,从一周前到现在读取数据,运行大约2秒;使用差的查询优化器选项,大约需要6分半钟。
那么问题是:为什么会这样做?为什么它不接受JOIN子句中存在3个表的强制索引条件,但只有2个? 我的MySQL服务器版本是5.6.34。
编辑:建议应用。将Link添加到所有涉及的表的创建查询中。
EDIT2:将查询更改为不使用dm_date_booking,这是一个视图,但是dm_date表,它是从视图数据中提取的实际表。