MySQL Join使查询变慢-无法弄清原因

时间:2018-12-27 08:05:27

标签: mysql

我将为一个旧查询和该查询的新版本附加两个Explain语句的结果。

您看到没有任何意义或看起来不对的东西吗?添加tm,tsa和tcd表后,查询变慢(4.5秒)。

enter image description here

在将这三个表添加到查询之前,它非常快(0.001秒)。这是解释的样子

enter image description here

tm表具有四列(tm_id(PK),owner_id,manager_id,状态),tcd具有三列(tm_id,cd_id,created_date)。 tm_id和cd_id组成一个复合主键,并且cd_id上还有另一个索引。与tsa具有三列(tm_id,smpa_id,created_date)的情况相同,其中tm_id和smpa_id是复合主键,而smpa_id具有另一个索引。

如此缓慢的原因可能是什么?

旧查询:

SELECT upcm_id, COUNT( * ) 
FROM user_post_content_master AS upcm
JOIN content_deck AS cd ON cd.cd_id = upcm.cd_id
JOIN social_media_post_account AS smpa ON smpa.smpa_id = upcm.smpa_id
JOIN post_content_master AS pcm ON pcm.pcm_id = upcm.pcm_id
WHERE smpa.user_id =2196
AND upcm.upcm_post_date >=1545891957
AND upcm.upcm_status =1
AND upcm.upcm_post_date >=1546560000
AND upcm.upcm_post_date <=1546732799
GROUP BY upcm.upcm_id
ORDER BY upcm.upcm_post_date ASC

新查询:

SELECT upcm_id, COUNT( * ) 
FROM user_post_content_master AS upcm
JOIN content_deck AS cd ON cd.cd_id = upcm.cd_id
JOIN social_media_post_account AS smpa ON smpa.smpa_id = upcm.smpa_id
JOIN post_content_master AS pcm ON pcm.pcm_id = upcm.pcm_id
JOIN team_content_deck AS tcd ON ( tcd.cd_id = upcm.cd_id ) 
JOIN team_social_account AS tsa ON tsa.smpa_id = upcm.smpa_id
JOIN team_members AS tm ON tm.team_member_id = tsa.team_member_id
AND tm.team_member_id = tcd.team_member_id
AND tm.owner_id =2196
AND tm.manager_id =2196
AND tm.status =1
WHERE smpa.user_id =2196
AND upcm.upcm_post_date >=1545891957
AND upcm.upcm_status =1
AND upcm.upcm_post_date >=1546560000
AND upcm.upcm_post_date <=1546732799
GROUP BY upcm.upcm_id
ORDER BY upcm.upcm_post_date ASC

如果我从tm表中删除条件,它又很快了。联接中没有任何变化。

EXPLAIN SELECT upcm_id, COUNT( * ) 
FROM user_post_content_master AS upcm
JOIN content_deck AS cd ON cd.cd_id = upcm.cd_id
JOIN social_media_post_account AS smpa ON smpa.smpa_id = upcm.smpa_id
JOIN post_content_master AS pcm ON pcm.pcm_id = upcm.pcm_id
JOIN team_content_deck AS tcd ON ( tcd.cd_id = upcm.cd_id ) 
JOIN team_social_account AS tsa ON tsa.smpa_id = upcm.smpa_id
JOIN team_members AS tm ON tm.team_member_id = tsa.team_member_id
AND tm.team_member_id = tcd.team_member_id
WHERE smpa.user_id =2196
AND upcm.upcm_post_date >=1545891957
AND upcm.upcm_status =1
AND upcm.upcm_post_date >=1546560000
AND upcm.upcm_post_date <=1546732799
GROUP BY upcm.upcm_id
ORDER BY upcm.upcm_post_date ASC

enter image description here

1 个答案:

答案 0 :(得分:1)

我看到差异很可能是因为为upcm选择了键,为旧查询选择了upcm_post_date,而新查询选择了cd_id。

由于数据不足,从名称上看,与upcm_post_date相比,cd_id的基数似乎要低得多。

更新(摘自下面的评论):

一个可能的原因是由于mysql为查询确定的表顺序,content_deck在user_post_content_master之前。由于mysql对JOIN使用嵌套循环算法,因此user_post_content_master位于连接的内部循环中。

当存在tm.owner_id时,您将进行恒定查找,这将导致MySQL优化器确定它胜过范围扫描。

在《高性能MySQL》一书中,有一章讨论了查询优化。有一种技术称为:联接分解,即将一个大联接查询分隔为一个小联接查询。另一个好处是您可以缓存一些通用数据。

我不确定索引提示是否可以在这种情况下提供帮助(只是提示或强制MySQL将post_data用于upcm):SELECT * FROM user_post_content_master USE INDEX(upcm_post_date)