Laravel Collection::toArray() 触发额外的数据库查询
Laravel Collection::toArray() triggers extra database queries
让我们使用典型的 posts/tags 示例。假设我想提取一些帖子的详细信息。我是一个聪明的开发者,想限制数据库查询,所以我急于将关系加载到标签。
<?php
class Post extends Model {
public function tags() { return $this->belongsToMany(Tag::class); }
}
class Tag extends Model {
public function posts() { return $this->belongsToMany(Post::class); }
}
$posts = Post::query()->with("tags")->where("title", "like", "foo%")->get();
到目前为止,还不错。我的数据库的查询日志显示两个查询:
select * from `posts` where `title` like 'foo%' and `posts`.`deleted_at` is null;
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` in (19, 880, 1462, 2712, 2713, 2717);
我现在可以毫无问题地处理帖子和标签。例如,我可以 运行 此代码而无需任何进一步的数据库查询:
foreach ($posts as $post) {
echo $post->title . "(" . implode(",", $post->tags->pluck("name")->all()) . ")";
}
这告诉我关系中的数据已按预期保存到集合 $posts
中。
所以,我的问题是:为什么调用 $posts->toArray()
或 $posts->toJson()
会导致 另一个 查询我的枢轴 table for 集合中的每个项目,提取集合中已存储的相同数据?
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = 19 limit 1;
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = 880 limit 1;
...
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = 2717 limit 1;
有什么方法可以防止这些额外的查询发生吗?
您可能有一个访问器正在通过 $appends
属性 'appended' 访问模型数据。它可能正在使用关系方法并导致查询而不是使用关系的动态 属性。
让我们使用典型的 posts/tags 示例。假设我想提取一些帖子的详细信息。我是一个聪明的开发者,想限制数据库查询,所以我急于将关系加载到标签。
<?php
class Post extends Model {
public function tags() { return $this->belongsToMany(Tag::class); }
}
class Tag extends Model {
public function posts() { return $this->belongsToMany(Post::class); }
}
$posts = Post::query()->with("tags")->where("title", "like", "foo%")->get();
到目前为止,还不错。我的数据库的查询日志显示两个查询:
select * from `posts` where `title` like 'foo%' and `posts`.`deleted_at` is null;
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` in (19, 880, 1462, 2712, 2713, 2717);
我现在可以毫无问题地处理帖子和标签。例如,我可以 运行 此代码而无需任何进一步的数据库查询:
foreach ($posts as $post) {
echo $post->title . "(" . implode(",", $post->tags->pluck("name")->all()) . ")";
}
这告诉我关系中的数据已按预期保存到集合 $posts
中。
所以,我的问题是:为什么调用 $posts->toArray()
或 $posts->toJson()
会导致 另一个 查询我的枢轴 table for 集合中的每个项目,提取集合中已存储的相同数据?
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = 19 limit 1;
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = 880 limit 1;
...
select `tags`.*, `post_tag`.`post_id` as `pivot_post_id`, `post_tag`.`tag_id` as `pivot_tag_id`
from `tags` inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where `post_tag`.`post_id` = 2717 limit 1;
有什么方法可以防止这些额外的查询发生吗?
您可能有一个访问器正在通过 $appends
属性 'appended' 访问模型数据。它可能正在使用关系方法并导致查询而不是使用关系的动态 属性。