如何高效合并两个SQL查询生成用户关注用户与话题的内容feed
合并SQL查询生成用户Feed的最优方案
最终合并后的查询代码
$query = " SELECT * FROM ( -- 拉取关注用户发布的帖子 SELECT t.t_id, t.t_thought, t.t_timestamp, t.u_id AS t_u_id, t.t_statistics, t.t_reaction, t.t_comments, t.t_no_reactions, t.t_no_comments, u.u_id AS u_u_id, u.u_username, u.u_real_name, u.u_profile_picture, r.r_id FROM thoughts AS t INNER JOIN users AS u ON t.u_id = u.u_id INNER JOIN followers AS f ON f.u_id = '".$u_id."' LEFT OUTER JOIN reactions AS r ON r.u_id = ? AND r.t_id = t.t_id WHERE t.u_id = f.u_id_to_follow UNION DISTINCT -- 拉取关注话题下的帖子 SELECT t.t_id, t.t_thought, t.t_timestamp, t.u_id AS t_u_id, t.t_statistics, t.t_reaction, t.t_comments, t.t_no_reactions, t.t_no_comments, u.u_id AS u_u_id, u.u_username, u.u_real_name, u.u_profile_picture, r.r_id FROM thoughts AS t INNER JOIN users AS u ON t.u_id = u.u_id INNER JOIN thoughts_tags AS tt ON tt.t_id = t.t_id LEFT OUTER JOIN reactions AS r ON r.u_id = ? AND r.t_id = t.t_id WHERE tt.tag_id IN( SELECT tag_id FROM tags_followers WHERE u_id = '".$u_id."') GROUP BY t.t_id ) AS combined_feed ORDER BY t_id DESC LIMIT ?, ? ";
注意:参数绑定时需要按顺序传入2次当前用户ID,再传入分页偏移量、分页条数两个参数。
方案最优性说明
- 复用原有成熟逻辑:两个子查询都是已经验证过可正常返回结果的逻辑,不需要修改原有查询的关联条件,改造成本极低,后续单独调整关注用户/关注话题的过滤规则时也不会互相影响。
- 去重逻辑可控:用
UNION DISTINCT自动过滤同时满足「关注用户发布」和「属于关注话题」的重复帖子,不需要额外在业务层做去重处理;如果不需要去重、追求更高性能可以换成UNION ALL,性能比UNION DISTINCT高30%左右。 - 统一排序分页效率更高:把排序和分页放在外层统一处理,比分别查询两个列表再在业务层合并排序、裁切的内存开销小很多,尤其是Feed拉取的分页条数一般在20-50条的场景下,性能损耗可以忽略。
- 可扩展性强:后续如果要加其他Feed源(比如官方推荐帖子、好友点赞的帖子),直接在UNION后面加对应子查询即可,不需要重构整体逻辑。
- 冗余逻辑清理:原话题查询中冗余关联了
tags表,没有用到该表的任何字段,合并时已经移除,减少不必要的关联开销。
可选性能优化建议
如果要进一步提升查询速度,可以做两个小调整:
- 把话题查询里的
IN(子查询)改成INNER JOIN tags_followers tf ON tf.tag_id = tt.tag_id AND tf.u_id = '".$u_id."',避免子查询生成临时表的开销。 - 给
followers.u_id、tags_followers.u_id、thoughts.t_id添加联合索引,能进一步降低关联查询的耗时。
内容的提问来源于stack exchange,提问作者Niels Hermann
相关产品推荐
相关产品推荐

