为啥 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?