如何判断帖子是否被当前用户保存并在前端展示对应状态标识?
两种方案优劣对比
方案一:前端侧ID比对
- 优势:SQL逻辑简单,帖子列表查询和用户收藏ID查询可以分开做缓存;如果用户收藏量小、分页帖子数少的场景下,前端比对开销几乎可以忽略。
- 劣势:当用户收藏量达到数千甚至上万级时,接口返回的收藏ID列表体积大,既占用带宽,也会增加前端内存开销;多端适配时还要重复实现比对逻辑,一致性维护成本高。
方案二:数据库子查询判断
- 优势:逻辑全部收敛在服务端,前端直接拿字段渲染即可,不需要额外处理,不存在收藏量过大的性能问题。
- 劣势:你当前写的是相关子查询,每返回一条帖子就要执行一次子查询,当分页帖子数较多时查询效率很低;同时你提供的SQL存在语法错误:
FROM后缺失表名、users_saved_posts是表名不是字段,无法直接运行。
更优实现方案
1. 优先优化关联表结构
你现在分两张关联表的设计冗余且不必要,用户和帖子的多对多收藏关系,直接用一张中间表就能实现,还能大幅降低查询复杂度:
CREATE TABLE user_saved_posts ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL REFERENCES users(id), post_id INT NOT NULL REFERENCES posts(id), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 联合唯一索引避免同一用户重复收藏同一帖子 UNIQUE KEY uk_user_post (user_id, post_id), -- 加速关联查询的索引 INDEX idx_user_id (user_id), INDEX idx_post_id (post_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2. 改用LEFT JOIN查询,效率远高于相关子查询
优化后的查询语句,一次联表就能拿到结果,只要索引建对,查询速度和单表查帖子列表基本持平:
SELECT p.*, CASE WHEN usp.user_id IS NOT NULL THEN TRUE ELSE FALSE END AS is_post_saved FROM posts p LEFT JOIN user_saved_posts usp ON usp.post_id = p.id AND usp.user_id = $1 -- $1替换为当前登录用户的ID -- 这里加你的分页、筛选条件,比如 LIMIT 10 OFFSET 0
如果暂时不想改动现有表结构,兼容你当前设计的优化查询语句如下:
SELECT p.*, CASE WHEN sp.post_id IS NOT NULL THEN TRUE ELSE FALSE END AS is_post_saved FROM posts p LEFT JOIN user_saved_posts usp ON usp.user_id = $1 LEFT JOIN saved_post sp ON sp.user_saved_post_id = usp.id AND sp.post_id = p.id
内容的提问来源于stack exchange,提问作者Iskaa
相关产品推荐
相关产品推荐

