laravel 5.5 上的预加载冲突
Eager loading conflict on laravel 5.5
我不是很明白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');
}
根据 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个查询,类似于普通的延迟加载!
有什么问题??
您正在创建其他查询而不是使用加载的数据,因此请使用 $channel->tags
集合而不是 $channel->tags()
:
foreach ($all_channels as $channel) {
echo 'Channel: ' . $channel->id . '<br>';
foreach ($channel->tags as $tag) {
echo 'Tag: ' . $tag->id . '<br>';
}
}
我不是很明白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');
}
根据 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个查询,类似于普通的延迟加载!
有什么问题??
您正在创建其他查询而不是使用加载的数据,因此请使用 $channel->tags
集合而不是 $channel->tags()
:
foreach ($all_channels as $channel) {
echo 'Channel: ' . $channel->id . '<br>';
foreach ($channel->tags as $tag) {
echo 'Tag: ' . $tag->id . '<br>';
}
}