由于另一个JOIN,MySQL强制索引无法正常工作

时间:2018-04-17 16:36:05

标签: mysql

到目前为止,我已阅读有关我的问题的thisthis链接,但无法完全理解这里发生了什么。这是查询:

 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行

上面的查询结果为:

result of original query

这里有两个主要问题,虽然我只对一个感兴趣。第一个是未使用指示的可能密钥(与其名称所建议的相应列相关)。关于这一点,这里有很多关于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;

结果是

changed result, now using index

当我从查询中删除dm_routes表时会发生等效。

为了获取我需要加入的所有表,我必须删除连接的一个表,然后将此选择查询作为子查询,然后将缺少的表连接到已经聚合的结果组。这意味着,我已经执行了两个变通办法(使用FORCE INDEX,然后创建子查询)以绕过MySQL查询优化器失败。

比较结果,使用我的解决方法,查询,从一周前到现在读取数据,运行大约2秒;使用差的查询优化器选项,大约需要6分半钟。

那么问题是:为什么会这样做?为什么它不接受JOIN子句中存在3个表的强制索引条件,但只有2个? 我的MySQL服务器版本是5.6.34。

编辑:建议应用。将Link添加到所有涉及的表的创建查询中。

EDIT2:将查询更改为不使用dm_date_booking,这是一个视图,但是dm_date表,它是从视图数据中提取的实际表。

0 个答案:

没有答案