我真的不明白laravel的方法是什么才能加载并解决N + 1查询的问题以及引擎盖下的问题。所以我自己决定测试结果!
所以我设计了一个简单的多对多关系,每个tgchannel(电报频道)都有很多标签,每个标签都有很多tgchannel。
namespace App;
use Illuminate\Database\Eloquent\Model;
class tgchannel extends Model
{
public function tags() {
return $this->belongsToMany('App\tag');
}
}
/////////////////////////////
class tag extends Model
{
//
public function tgchannels() {
return $this->belongsToMany('App\tgchannel');
}
我使用eager loading来加载控制器方法中的标签关系,根据laravel文档和输出结果sql使用这种技术:
public function test()
{
$all_channels = tgchannel::with(['tags'])->toSql();
echo $all_channels.'<br>';
$all_channels = tgchannel::with(['tags'])->get();
foreach ($all_channels as $channel) {
$sql = $channel->tags()->toSql();
echo $sql.'<br>';
}
}
在测试数据库中,我有12个tgchannels,每个都有一个标签。最后这是结果:
select * from `tgchannels`
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
select * from `tags` inner join `tag_tgchannel` on `tags`.`id` = `tag_tgchannel`.`tag_id` where `tag_tgchannel`.`tgchannel_id` = ?
你可以看到执行的查询不是2,并且执行的N + 1查询类似于常见的延迟加载!
问题是什么?
答案 0 :(得分:2)
您正在创建其他查询而不是使用已加载的数据,因此请使用$channel->tags
集合代替$channel->tags()
:
foreach ($all_channels as $channel) {
echo 'Channel: ' . $channel->id . '<br>';
foreach ($channel->tags as $tag) {
echo 'Tag: ' . $tag->id . '<br>';
}
}