应优先在数据库层用 distinct() 去重,高效省资源;php 层 unique() 仅适用于已加载数据或需灵活处理的场景,大数据量时易内存溢出。

直接用 distinct(),但得看你在哪一层去重——数据库层还是 PHP 集合层。前者快、省资源;后者灵活但吃内存,大数据量时容易崩。
用 distinct() 在数据库层去重
这是最常用也最推荐的方式,Laravel 会生成 SELECT DISTINCT SQL,由数据库完成过滤。
- 只取一个字段的唯一值:
BlogModel::select('user_id')->distinct()->pluck('user_id')->toArray() - 带条件去重:
BlogModel::where('status', 'active')->select('category')->distinct()->get() - 多字段组合去重(只有所有字段值完全相同时才视为重复):
DB::table('orders')->select('user_id', 'country')->distinct()->get()
⚠️ 注意:distinct() 作用于整个 select() 列表。如果你写了 select('user_id', 'created_at'),那两列值都一样才算重复;想单按 user_id 去重并保留最新一条记录,得换 groupBy('user_id')->latest('created_at') 或窗口函数。
用 unique() 在集合层去重
当数据已经查出来、或者必须在 PHP 中处理(比如合并多个查询结果),才用这个。
- 对单字段去重:
collect($results)->unique('user_id') - 对整个数组项去重(需转成对象或指定回调):
collect($items)->unique(function ($item) { return $item['user_id'] . '_' . $item['status']; }) - 去重后重置键:
->unique('user_id')->values()->toArray(),否则键可能不连续
⚠️ 避免这样写:BlogModel::get()->unique('user_id') —— 它会先把全表加载进内存再过滤,10 万条记录就可能 OOM。
distinct('field') 是 Laravel 10.28+ 新增语法
这个写法看起来像“按某字段去重”,但它其实只是语法糖,底层仍等价于 select('field')->distinct(),不能替代 groupBy 实现“每组取一条完整记录”的需求。
- ✅ 正确用法:
BlogModel::distinct('user_id')->pluck('user_id') - ❌ 错误期待:以为它能返回每个
user_id对应的最新博客全文(实际只返回 ID)
如果真要“按 user_id 取最新一条完整记录”,得用 groupBy('user_id')->orderByDesc('created_at')->get(),并确保数据库模式允许(MySQL 5.7+ 严格模式下需配合聚合或子查询)。
真正容易被忽略的是层级选择:90% 的去重需求,都应该压到数据库层做;剩下 10% 才轮到集合层。别让 unique() 成为性能瓶颈的遮羞布。











