优化MySQL多表查询性能:获取关注卖家商品并统计互动数据
优化关注卖家商品查询的实用方案
我懂你现在的痛点——用WHERE IN筛选关注卖家的商品时,查询速度慢得让人着急,还要顺便统计点赞、评论数,确实容易卡。结合你说的所有ID都是键的情况,给你整理几个落地性强的优化思路:
1. 把WHERE IN换成JOIN,让索引真正发挥作用
WHERE IN尤其是嵌套子查询的写法,很多时候数据库优化器没法高效利用索引,尤其是当关注的卖家数量多的时候。换成JOIN关联关注表和商品表,能直接用上你已有的主键/索引:
比如原来你可能写的是:
SELECT ... FROM produtos p WHERE p.user IN (SELECT seller_id FROM follows WHERE user_id = '当前用户ID')
改成JOIN的写法:
SELECT ... FROM produtos p JOIN follows f ON p.user = f.seller_id WHERE f.user_id = '当前用户ID'
这样数据库会优先用follows表的(user_id, seller_id)联合索引快速定位你关注的卖家,再通过produtos表的user索引(卖家ID)拉取对应商品,比IN的效率高很多。
2. 别实时COUNT(DISTINCT),换个姿势统计点赞/评论数
实时用COUNT(DISTINCT)统计点赞和评论数是性能杀手,数据量一大就卡。这里有两个实用方向:
- 异步预统计:在
produtos表加两个字段likes_count和comments_count,然后用触发器(比如用户点赞时自动+1)或者异步任务(比如消息队列处理点赞/评论事件)来更新这两个字段。查询的时候直接取字段值,不用再实时计算,速度飞起。 - 预聚合子查询:如果必须实时统计,别在主查询里嵌套COUNT,先单独聚合点赞/评论数据,再和主查询JOIN:
-- 先预聚合点赞数 WITH likes_agg AS ( SELECT p_id, COUNT(DISTINCT user) AS likes_count FROM likes GROUP BY p_id ), comments_agg AS ( SELECT p_id, COUNT(DISTINCT user) AS comments_count FROM comenta GROUP BY p_id ) SELECT c.nome, p.foto, c.user, p.user, p.id, p.data, p.titulo, p.youtube, pp.foto, COALESCE(l.likes_count, 0) AS likes_count, COALESCE(com.comments_count, 0) AS comments_count FROM produtos p JOIN follows f ON p.user = f.seller_id JOIN clientes c ON c.user = f.user_id LEFT JOIN likes_agg l ON p.id = l.p_id LEFT JOIN comments_agg com ON p.id = com.p_id LEFT JOIN pp ON pp.p_id = p.id WHERE f.user_id = '当前用户ID'
这样聚合操作是单独完成的,比在主查询里带COUNT的效率高不少,用COALESCE还能处理没有点赞/评论的商品,返回0而不是NULL。
3. 给索引“补补课”,确保关键路径都有索引
既然所有ID都是键,那要确保这些索引能被用到:
follows表:建联合索引(user_id, seller_id),查询当前用户关注的卖家时能直接命中,不用全表扫描。produtos表:建索引(user)(卖家ID),JOIN时快速定位该卖家的所有商品。likes和comenta表:建联合索引(p_id, user),这样聚合统计的时候能快速按商品ID分组,避免全表扫描。
4. 大数据量下别忘了分页
如果用户关注的卖家特别多,商品总量很大,一次性拉取所有数据肯定慢。用LIMIT做分页,或者更高效的游标分页(比如基于最后一条商品的id和data来分页),减少单次查询的数据量,响应速度会快很多。
优化后的完整示例语句
结合上面的思路,给你写个完整的优化版参考:
SELECT c.nome, p.foto, c.user AS customer_user, p.user AS seller_user, p.id, p.data, p.titulo, p.youtube, pp.foto AS related_photo, COALESCE(l.likes_count, 0) AS likes_count, COALESCE(com.comments_count, 0) AS comments_count FROM produtos p JOIN follows f ON p.user = f.seller_id JOIN clientes c ON c.user = f.user_id LEFT JOIN (SELECT p_id, COUNT(DISTINCT user) AS likes_count FROM likes GROUP BY p_id) l ON p.id = l.p_id LEFT JOIN (SELECT p_id, COUNT(DISTINCT user) AS comments_count FROM comenta GROUP BY p_id) com ON p.id = com.p_id LEFT JOIN pp ON pp.p_id = p.id WHERE f.user_id = '你的当前用户ID' ORDER BY p.data DESC LIMIT 20 OFFSET 0; -- 分页参数,根据需求调整
内容的提问来源于stack exchange,提问作者RGS
相关产品推荐
相关产品推荐

