SQL左连接查询性能优化求助:如何利用索引提速统计查询?
咱们来一步步拆解你的问题,找到让查询提速的关键点:你的核心需求是统计用户ID=2未忽略的、属于forum_id=1的主题数,现有查询慢的根源其实在索引的设计匹配度上,下面是具体的优化思路:
1. 给topics_ignore建复合索引(最关键的一步)
你现在给topics_ignore只建了topic_id的单字段索引,但查询里是同时用user_id=2和topic_id做关联过滤的。单字段索引在这里的效率很低——数据库需要先找到所有匹配topic_id的记录,再从中筛出user_id=2的,相当于多做了一次过滤。
换成**复合索引(user_id, topic_id)**就不一样了:数据库可以直接定位到用户ID=2的所有忽略主题,不用额外过滤,关联时的查找速度会飙升。
执行这条SQL创建索引:
CREATE INDEX idx_topics_ignore_user_topic ON topics_ignore(user_id, topic_id);
2. 优化topics表的索引(锦上添花)
你的topics表现有topic_id和forum_id的单字段索引,其实可以合并成复合索引(forum_id, topic_id)。因为你的查询第一步是筛选forum_id=1,这个复合索引能让数据库直接取出该论坛下的所有topic_id,不用先查forum_id索引再回表取topic_id,减少了IO开销。
创建索引的SQL:
CREATE INDEX idx_topics_forum_topic ON topics(forum_id, topic_id);
3. 换用NOT EXISTS写法(小数据集下更高效)
因为topics_ignore只有33条数据,用NOT EXISTS的写法有时候会比左连接+IS NULL更高效,数据库的优化器可能会选择更轻量的执行计划,逻辑上和原查询完全等价:
SELECT COUNT(t.topic_id) AS num_topics FROM topics t WHERE t.forum_id = 1 AND NOT EXISTS ( SELECT 1 FROM topics_ignore i WHERE i.topic_id = t.topic_id AND i.user_id = 2 );
为什么原查询慢?
再回头看原查询的执行逻辑:数据库会先扫描topics表中forum_id=1的所有记录,然后对每条记录去topics_ignore的topic_id索引里查找,还要额外过滤user_id=2。这个过程中,每条topics的记录都要做一次“先找topic_id再筛user_id”的操作,累计起来就拖慢了速度。而复合索引(user_id, topic_id)直接把用户2的忽略主题打包成了一个小集合,关联时直接匹配,效率自然就上去了。
内容的提问来源于stack exchange,提问作者Lars Vegas




