我将为一个旧查询和该查询的新版本附加两个Explain语句的结果。
您看到没有任何意义或看起来不对的东西吗?添加tm,tsa和tcd表后,查询变慢(4.5秒)。
在将这三个表添加到查询之前,它非常快(0.001秒)。这是解释的样子
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
答案 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)