
本文介绍如何通过 sql 高效查询与指定用户互相关注的用户列表,并获取其完整资料,避免 laravel 中低效的嵌套循环方案。
本文介绍如何通过 sql 高效查询与指定用户互相关注的用户列表,并获取其完整资料,避免 laravel 中低效的嵌套循环方案。
在社交类应用中,“双向关注”(即互粉)是构建好友关系的核心逻辑。例如:用户 23 关注了用户 22,同时用户 22 也关注了用户 23 —— 这种对称关系即为互相关注。若仅用应用层(如 Laravel)遍历比对 UserFollowing 表的两组记录,时间复杂度为 O(n×m),数据量稍大即显著拖慢响应。
高效解决方案:使用自连接(Self-Join)一次性完成匹配
假设关注关系存储在 user_following 表中(字段含 id, follower_id, following_id),要找出所有与用户 X(如 id = 23)互相关注的用户,可执行以下标准 SQL:
SELECT DISTINCT u.id, u.name, u.email FROM user_following uf1 JOIN user_following uf2 ON uf1.follower_id = uf2.following_id AND uf1.following_id = uf2.follower_id JOIN users u ON u.id = uf1.follower_id WHERE uf1.following_id = 23; -- 用户X的ID(即“被谁关注且也关注了谁”)
✅ 执行逻辑说明:
-
uf1表示“用户 23 关注的人”(uf1.following_id = 23→uf1.follower_id是关注者); -
uf2表示“关注用户 23 的人”(uf2.follower_id = 23→uf2.following_id是被关注者); - 自连接条件
uf1.follower_id = uf2.following_id AND uf1.following_id = uf2.follower_id确保:A 关注 B,且 B 同时关注 A → 即
(A→B) ∧ (B→A)成立。
? 关键优化点:
- 使用
DISTINCT防止因多条关注记录导致重复; - 显式
JOIN users获取姓名、邮箱等扩展信息,替代多次User::find()查询; - 数据库索引建议:在
(following_id, follower_id)和(follower_id, following_id)上建立复合索引,大幅提升 JOIN 效率。
⚠️ 注意事项:
- 切勿在 Laravel 中沿用原始的双层
foreach+User::find()方案——它会触发 N+M 次数据库查询,严重违背 N+1 查询原则; - 若需排除用户自身(如防止
user_id = 23与自己互关),可在WHERE中追加AND uf1.follower_id != 23; - 生产环境务必对
user_following表的外键字段添加索引,否则自连接性能将随数据增长急剧下降。
通过一条结构清晰、语义明确的 SQL,即可精准、高效地提取双向关注用户全量信息,兼顾可读性与执行性能,是社交关系建模的典型实践范式。

















