在laravel 5.5上急切加载冲突

时间:2017-11-19 12:46:02

标签: php laravel many-to-many eager-loading

我真的不明白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查询类似于常见的延迟加载!

问题是什么?

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