为啥 MySQL JOIN 比 WHERE IN (子查询) 快得多

Posted

技术标签:

【中文标题】为啥 MySQL JOIN 比 WHERE IN (子查询) 快得多【英文标题】:why is MySQL JOIN significantly faster than WHERE IN (subquery)为什么 MySQL JOIN 比 WHERE IN (子查询) 快得多 【发布时间】:2010-11-17 17:11:38 【问题描述】:

我试图更好地理解为什么这种查询优化如此重要(快 100 倍以上),以便我可以将类似的逻辑重用于其他查询。

使用 mysql 4.1 - RESET QUERY CACHE 和 FLUSH TABLES 在所有查询和结果时间可以一致地重现之前完成。在 EXPLAIN 中对我来说唯一明显的是,在 JOIN 期间只需要找到 5 行吗?但这就是速度的全部答案吗?两个查询都使用部分索引 (forum_stickies) 来确定已删除主题的状态 (topic_status=0)

使用 EXPLAIN 进行更深入分析的屏幕截图

http://img195.imageshack.us/img195/9494/mysqlfaster.png

慢查询:0.7+ 秒(缓存清除)

SELECT SQL_NO_CACHE forum_id, topic_id FROM bb_topics 
WHERE topic_last_post_id IN 
(SELECT SQL_NO_CACHE  MAX (topic_last_post_id) AS topic_last_post_id
FROM bb_topics WHERE topic_status=0 GROUP BY forum_id)

快速查询:0.004 秒或更短(清除缓存)

SELECT SQL_NO_CACHE forum_id, topic_id FROM bb_topics AS s1 
JOIN 
(SELECT SQL_NO_CACHE MAX(topic_last_post_id) AS topic_last_post_id
FROM bb_topics WHERE topic_status=0 GROUP BY forum_id) AS s2 
ON s1.topic_last_post_id=s2.topic_last_post_id  

请注意,最重要的列 (topic_last_post_id) 上没有索引,但这无济于事(无论如何都会存储结果以供重复使用)。

答案仅仅是因为第一次查询必须扫描topic_last_post_id TWICE,第二次将结果匹配到子查询?如果是这样,为什么它会成倍地变慢?

(不太重要,我很好奇如果我真的在topic_last_post_id 上放置索引,为什么第一个查询仍然需要这么长时间)

更新:经过多次搜索后,我在 *** 上找到了这个线程,该线程进入了这个主题Subqueries vs joins

【问题讨论】:

【参考方案1】:

也许引擎对 bb_topics 中的每一行执行子查询,只是为了看看它是否在结果中找到了 topic_last_post_id。会很愚蠢,但也会解释巨大的差异。

【讨论】:

哇,这可能是可能的。我只考虑过它可能会查询组结果中的每个 id(其中 5 个),但现在你提到它,我想知道它是否对所有 209 行(甚至更糟糕的 293 行)都进行了查询。我向某人发送了一个请求,要求在更大的数据集(10,000 行 vs 300 行)上尝试查询,所以我看看问题是否会变得更加放大,这将证明这一理论。 我突然想到也试试这个简单的查询SELECT SQL_NO_CACHE forum_id, topic_id FROM bb_topics WHERE topic_last_post_id IN(1516,1567,1572,1569,1578),它非常快。所以你是对的,它正在为每一行执行子查询,哇,这太疯狂了。 这似乎在 5.6 中已修复(不再是 DEPENDENT SUBQUERY),性能类似于 JOIN。

以上是关于为啥 MySQL JOIN 比 WHERE IN (子查询) 快得多的主要内容,如果未能解决你的问题,请参考以下文章

为啥 MySQL LEFT JOIN 不返回所有行,除非有 WHERE 子句 - phpMyAdmin 问题

MySQL LEFT JOIN 或 WHERE IN SUBQUERY

强制 MySQL 从 WHERE IN 子句返回重复项而不使用 JOIN/UNION?

mysql where not in to left outer join

为啥 MySQL 不使用复合 WHERE IN 的索引?

为啥对三个表的联合 mysql 查询比在不可能的 where 子句上连接更快?