Laravel 9中从Eloquent关联获取唯一用户列表的优化方案
Laravel 9 关联用户唯一列表查询优化
方法一:反向关联直接查询(推荐,数据库层面处理,性能最优)
如果你的User模型中已经定义了与Item的关联关系(比如belongsToMany或hasMany),可以直接从User模型出发,过滤出关联了type为user的Item的用户,数据库会自动处理去重:
// 假设User模型的关联定义示例(根据实际关联类型调整): // public function items() // { // return $this->belongsToMany(Item::class); // } $uniqueUsers = User::whereHas('items', function ($query) { $query->where('type', 'user'); })->get();
这种方式不需要加载所有Item数据,直接在数据库层面完成过滤和去重,避免内存冗余,性能最佳。
方法二:集合方法简化现有逻辑(无需循环)
如果业务上必须先获取Item集合,可以用Laravel集合的flatMap方法替代手动循环,代码更简洁高效:
$items = Item::where('type', 'user')->with('users')->get(); $uniqueUsers = $items->flatMap(fn($item) => $item->users)->unique();
flatMap会自动将每个Item的users集合展开为一维集合,再调用unique()去重,比原代码的循环merge更简洁。
方法三:通过关联表直接查询
也可以直接通过关联表的JOIN操作,在数据库层面获取去重后的用户列表,适合不想依赖反向关联的场景:
// 注意:表名和关联字段需根据你的实际数据库结构调整 $uniqueUsers = Item::where('type', 'user') ->join('item_user', 'items.id', '=', 'item_user.item_id') // 关联中间表 ->join('users', 'users.id', '=', 'item_user.user_id') ->select('users.*') ->distinct() ->get();
原代码的冗余问题说明
原代码中已经用with('users')预加载了关联数据,但循环里又调用$item->users()->get(),这会触发N+1查询(每个Item都单独查一次用户),完全浪费了预加载的作用。哪怕不优化结构,也应该直接使用$item->users(预加载的集合)而非$item->users()->get()。
内容的提问来源于stack exchange,提问作者party-ring
相关产品推荐
相关产品推荐

