模型的预加载
预加载: 解决关联查询中产生的N+1
次查询带来的资源消耗
模型
php
class User extends Model
{
protected $table = 'user';
// 一对多关联 Book 表
public function books()
{
return $this->hasMany(Book::class, 'user_id', 'id');
}
}
class Book extends Model
{
protected $table = 'book';
// 反向关联
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
}
要获取所有书籍的作者(或拥有者),普通查询方案如下
php
//获取所有书籍列表
$books = Book::all();
//遍历每一本书
foreach ($books as $book) {
//每一本书的关联用户的姓名
DebugBar::info($book->user->username);
}
sql
-- N+1 条,就是起初获取全部数据的 1 条和,遍历的 N 条
select * from `book`
select * from `user` where `user`.`id` = ? limit 1
select * from `user` where `user`.`id` = ? limit 1
使用with()关键字,进行预载入设置,提前将SQL整合
php
//with 关键字预载入
$books = Book::with('user')->get();
foreach ($books as $book) {
DebugBar::info($book->user->username);
}
sql
select * from `book`
select * from `user` where `user`.`id` in (1)
php
// 预载入设置指定的列
$books = Book::with('user:id,name')->get();
sql
select * from `book`
select `id`, `name` from `user` where `user`.`id` in (1)
模型中定义默认加载的关联
php
class Book extends Model
{
protected $table = 'book';
// 默认加载的关联
protected $with = ['user'];
// 反向关联
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id');
}
}
预载入筛选
php
Book::with([
'user' => function ($query) {
$query->where('id', 1);
}
])->get();
sql
select * from `book`
select * from `user` where `user`.`id` in (1) and `id` = ?
延迟预载入
php
$books = Book::all();
$books->load('user');
sql
select * from `book`
select * from `user` where `user`.`id` in (1)
实现延迟关联统计
php
$users = User::all();
$users->loadCount('book');
sql
select * from `user`
select `id`,
(
select count(*) from `book` where `user`.`id` = `book`.`user_id`
) as `books_count`
from `user`
where `user`.`id` in (?, ?)
json
[
{
"id": 1,
"name": "曹真",
"age": 23,
"create_time": "2022-07-05 10:32:48",
"update_time": "2022-07-05 10:47:36",
"delete_time": null,
"books_count": 2
},
{
"id": 2,
"name": "曹丕",
"age": 21,
"create_time": "2022-07-05 10:36:47",
"update_time": "2022-07-05 10:47:22",
"delete_time": null,
"books_count": 0
}
]