laravel使用模型关联时,是否效率低于DB构造器

新手上路,请多包涵

QQ图片20200401193031.png
类似这种 我建立了一对一的模型
使用他的时候我需要$result = table::all();
然后
foreach($result as $data){
   $data->infotmation

这样子的话 就相当于先获取了第一个表 然后从遍历第一个表中的数据 根据第一个表中的数据 再次到T_ready表中去查 这样的话 是不是就相当于查询两次了 那感觉效率没有DB快啊 DB的话是不是使用一次就能获得最终结果了?是我哪里理解错了嘛 ? 还是用错了  求大佬解惑

阅读 4.1k
1 个回答

模型关联带来了便利,但是也在一定程度上牺牲了效率。
如果普通的一对一,我们可以用 left join 来进行解决,这样就是确保主表有数据,副表可能 null ,如果一对一要求两边都不能为 null ,那可以改成 inner join 。

普通的一对一,在 Laravel 中 如果使用不当,就会造成 N+1 的问题,但是 Laravel 为这个问题也是提供了解决方案,只是大多初学者没有认真的去读文档。
如果像你上面那样。

foreach(User::get() as $user){
    // some code
    $user->car_color = $user->car->color;
}

类似于这样的代码,在循环中直接调用了关联,就会造成 N+1,即除了上面的 User::get() 外,每次循环都会多执行一次查询 car 的关联语句,如果数据量大了这就是很大的一笔开支

但是可以用 with('car'),即 懒加载 - 模型关联,下面这样,就只是变成2次执行,第一次执行get 获取数据,第二次 pluck 关联列,然后使用 where in 去关联表查询,再使用程序去 merge。

foreach(User::with('car')->get() as $user){
    // some code
    $user->car_color = $user->car->color;
}

这样的问题就是会出现 car 找不到为 null 的情况,当然,你可以在定义一对一关联时使用 withDefault(),这个方法来给他一个默认值, 当然如果你要实现 inner 的效果,你就需要使用上面提到的 has。

foreach(User::with('car')->has('car')->get() as $user){
    // some code 
}

这样 Laravel 会构造一条 exists 来进行处理,由此可见,虽然这样的代码更加清晰,开发、维护起来更加便利,但是确实牺牲了效率,由一条查询变成了多条查询,甚至,有文章指出,使用 has 时,产生的 exists 还会存在遍历主表的情况。

如果你对 Laravel 中的数据库执行记录有兴趣,你可以在你的项目装一个记录 SQL 的扩展包,又或者,你可以直接安装一个 Laravel-debugger ,它可以提供更多的功能,但是请注意,不要在生产环境中使用它。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题