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>';
    }
}