Laravel 中 Query Builder 与 Collection 有什么区别
Query Builder 是 SQL 构造器,操作发生在数据库;Collection 是 PHP 内存中的数组增强包装,操作发生在应用层。get() 是分水岭:之前是 Builder,之后是 Collection。
一句话回答:Query Builder(查询构造器)用于在数据库层面构造和执行 SQL,where()、orderBy() 等调用最终翻译成 SQL 语句;Collection(集合)是数据取回内存后的增强数组,提供 map()、filter()、chunk() 等链式方法。get() 通常返回 Collection;first() 返回单个对象/模型或 null,paginate() 返回分页器,不能统称为 Collection。
版本范围:以下 Laravel 示例按 12.x 官方文档核对;其他版本请检查对应 API 与配置差异。
各是什么
Query Builder——应用与数据库之间的抽象层,提供跨数据库的统一 API:
$users = DB::table('users')
->where('votes', '>=', 100) // 翻译成 SQL 的 WHERE
->orderBy('created_at')
->get(); // ← 这一刻 SQL 才真正执行
Collection——对 PHP 数组的面向对象包装,提供流畅的链式数据处理:
$collection = collect(str_split('AABBCCCD'));
$chunks = $collection->chunkWhile(function ($value, $key, $chunk) {
return $value === $chunk->last();
});
$chunks->map(fn ($chunk) => $chunk->values()->all())->all();
// [['A','A'], ['B','B'], ['C','C','C'], ['D']]
核心区别
| 维度 | Query Builder | Collection |
|---|---|---|
| 操作位置 | 数据库(生成 SQL) | PHP 内存 |
| 数据量 | 只取需要的数据 | 已取回的全部数据 |
| 典型方法 | where() join() groupBy() get() |
map() filter() pluck() chunk() |
| 性能特征 | 可利用索引,实际性能取决于执行计划 | 大集合占应用内存,小集合变换也可能更合适 |
| 求值 | where/orderBy 构造查询,get/first 等触发执行 | 普通 Collection 通常已载入;LazyCollection 另有惰性语义 |
同名方法的不同语义——最容易踩的坑
Builder 和 Collection 都有 where()、pluck() 等方法,但行为完全不同:
// Builder:WHERE created_at > '2024-01-01' 下推到数据库,只取需要的行
DB::table('orders')->where('created_at', '>', '2024-01-01')->get();
// Collection:先 get() 取回全部 100 万行,再在内存里过滤 —— 灾难
DB::table('orders')->get()->where('created_at', '>', '2024-01-01');
原则:能在数据库做的事(过滤、排序、聚合、分页),绝不留到 Collection 里做。 Collection 适合的是取回后的变换、分组展示、计算派生数据。
Eloquent 的位置
Eloquent 模型查询返回的是 Illuminate\Database\Eloquent\Collection(继承自基础 Collection,多了模型相关方法如 load() 预加载)。User::where(...)->get() 先走 Builder,get() 后得到 Eloquent Collection,规则相同。
常见问题(FAQ)
Q:怎么判断当前链式调用的是 Builder 还是 Collection?
A:看终结方法与返回类型:Query Builder 的 get() 是基础 Collection,Eloquent 的 get() 是模型集合;first() 是 stdClass/模型或 null;paginate() 是 LengthAwarePaginator。可用 get_debug_type($x) 检查,null 不能传给 get_class()。
Q:DB::table() 和 User:: 查询有什么区别?
A:DB::table() 返回 Query Builder,调用 get() 才返回基础 Collection(元素是 stdClass);User::where() 返回 Eloquent Builder,get() 才返回模型集合。
Q:Collection 方法太多记不住怎么办?
A:可先熟悉这些常用方法:map filter pluck groupBy sortBy chunk first count sum toArray。其余用时查文档。
核查依据
本文依据官方文档核对,示例未在实际业务环境运行;上线前请按部署版本、权限与数据范围验证。