Laravel文档中Eager Loading section的第一句话是:
当访问Eloquent关系作为属性时,关系 数据是"延迟加载"。这意味着关系数据不是 实际加载,直到你第一次访问该属性。
在本节的最后一段中陈述:
要仅在尚未加载关系时加载关系,请使用 loadMissing方法:
public function format(Book $book)
{
$book->loadMissing('author');
return [
'name' => $book->name,
'author' => $book->author->name
];
}
但我没有看到$book->loadMissing('author')
的目的。这是在做什么吗?
如果我删除此行会有什么区别?根据第一句话,$book->author->name
中的作者无论如何都会懒惰,对吗?
答案 0 :(得分:7)
非常好的问题;通过阅读文档可以立即反映出微妙的差异。
您正在比较" Lazy Eager Loading"使用loadMissing()
到"延迟加载"在模型上使用magic properties。
顾名思义,唯一的区别在于:
因此,实际上,除非您希望在使用之前明确加载关系,否则没有区别。
值得注意的是,load
和loadMissing
方法都允许您通过传递闭包来自定义关系加载逻辑,该闭包在使用魔术属性时不是一个选项。
$book->loadMissing(['author' => function (Builder $query) {
$query->where('approved', true);
}]);
哪个转换为"如果尚未加载,则加载缺失的已批准作者" 除非您在$book->author
上定义approvedAuthor
关系,否则使用$book->loadMissing('author');
无法实现模型(这是一种更好的做法)。
直接回答你的问题;是的,如果你删除了,那将会有什么不同:
$book = Book::with('author')->find($id);
在该特定示例中,因为它在加载后立即使用。但是,可能很少有用户希望在使用之前加载关系。
因此,要概述关系加载方法的工作原理:
通过with()
的使用,您可以"急切加载"查询父模型时的关系:
$book->load('author');
在 之后,急切地加载关系:
$book->loadMissing('author');
也可能只用于加载遗漏的方法:
import csv
import json
infile = open("top40nl.json", "r")
outfile = open("top40nl.csv", "w")
writer = csv.writer(outfile)
for row in json.loads(infile.read()):
writer.writerow(row)
与load()
方法相反,loadMissing()
方法通过给定的关系过滤并且懒洋洋地"渴望"仅在尚未加载时加载 。
通过接受闭包,两种方法都支持自定义关系加载逻辑。
通过使用magic properties进行的延迟加载是为了方便开发人员。它会根据其使用情况加载关系,因此您无需事先加载它。
@rzb也在his answer中提到了一个非常好的观点。看看。
答案 1 :(得分:2)
我认为接受的答案缺少一个可能误导某些事实的重要事实:你无法在集合上运行loadMissing($relation)
。
这很重要,因为大多数惰性加载关系的使用案例都是当你已经拥有一个集合并且你不想提交n + 1 sin时 - 即在一个循环中不必要地多次命中DB。
因此,虽然您可以在集合上使用load($relation)
,但如果您只想在以前尚未加载关系的情况下执行此操作,则表示您运气不佳。
答案 2 :(得分:0)
假设你有多种关系。
图书属于作者,图书属于出版商。
所以首先你可以用一种关系加载它。
$books->load('author');
以后在某种情况下你想加载另一个关系。
$book->loadMissing('publisher');
但我没有看到$ book-> loadMissing('author');的目的。是吗 在这做什么?如果我删除会有什么不同 这条线?根据第一句,作者在 无论如何,$ book-> author->名称都会延迟加载,对吧?
假设说
public function format(Book $book)
{
//book will not have the author relationship yet
return [
'name' => $book->name, //book will not have the author relationship loaded yet
'author' => $book->author->name //book will now have the author relationship
];
}
上下代码之间的差异是加载关系的时间以及对属性的控制程度。
public function format(Book $book)
{
$book->loadMissing('author'); // book will now have the author relationship
return [
'name' => $book->name, // book have the author relationship loaded
'author' => $book->author->name // book have the author relationship loaded
];
}
答案 3 :(得分:0)
这里的两个答案都很好地涵盖了技术差异,所以我先给大家介绍一下。但“为什么”并不是很明显。
我最近发现自己的一些东西是,Eloquent非常擅长给你足够的绳索来吊死自己。通过抽象开发人员远离生成的实际SQL查询,特别是动态属性,很容易忘记当你的数据库命中对你的性能造成的损害超过他们所需要的时候。
这就是事情。对1000个值使用IN()
语句的一个查询与在一个值上运行的一个查询执行的执行时间大致相同。 SQL非常擅长它的功能 - 通常会打开和关闭数据库连接。这有点像去购买每个项目的市场之旅去购买杂货,而不是一次性完成。预加载使用IN语句。
延迟加载适用于处理服务器RAM需要处理太多数据的情况,并且在我看来,对其他方面并不好。它在任何给定时刻只处理一个条目。但它每次重新连接。我不能告诉你我看过Transformer类的次数,它应该只负责重新格式化数据而不是检索数据,利用这些动态属性并且没有意识到数据不存在。我看到改进只是通过在调用Transformer之前添加一行预先加载来将执行时间从30分钟缩短到30秒。
(顺便说一句,批处理可能被认为是快乐的媒介,而Eloquent的chunk()
方法也提供了这种方法。)
更直接地回答你的问题;如果你正在处理一个一对一关系的实例,并且只在一个地方使用它,那么在功能上load
,loadMissing
或者a之间没有区别延迟加载动态属性。但是如果你有多对多,那么同时收集所有数据可能是值得的。一本书可以有很多共同作者。一位作者可以写很多书。如果您即将完成大量任务,请在开始烹饪之前充分利用您的市场之旅。
答案 4 :(得分:0)
表示不重复查询 要清楚一点 如果您使用:load()2次,即使存在关系,查询也会重复
while:loadMissing()检查关系是否已加载。它不会重复查询。因为它之前已经通过[load()或with()] = egear load
加载过 DB::enableQueryLog();
$user = User::find(1);
// see the query
$user->load('posts');
$user->load('posts');
$user->loadMissing('posts'); // put it on top to see the difference
dd(DB::getQueryLog());
这就是我认为的目的
答案 5 :(得分:0)
在API环境中使用with
,loadMissing
或load
时,将其更重要,因为API环境会将结果传递给json
。在这种情况下,延迟加载没有任何作用。