我有这个结构:
学校 - > hasMany - > Classes
所以当我尝试下面的代码时 artisan tinker
App\School::with('schoolclasses')->find(2283)->schoolclasses;
我可以毫无问题地获得课程.
但是当我尝试没有使用时,我仍然可以得到相同的结果而没有问题:
App\School::find(2283)->schoolclasses;
是否Eloquent
急于加载?如果是这样,如何禁用它?
不,Laravel默认情况下并不急于加载.让我们一步一步来.让我们->schoolclasses;
暂时忽略.
App\School::with('schoolclasses')->find(2283);
这将两次查询数据库.首先,它将获得School
2283的主键.然后,它将立即查询数据库并获得所有相关的schoolclasses
.
App\School::find(2283);
这只会查询一次数据库.它只会得到School
.到目前为止还没有急切的加载.如果您调试并跟踪数据库查询,您将看到这只会查询数据库一次,而急切加载将查询它两次.
当您尝试访问该schoolclasses
做->schoolclasses;
,一切实际工作.那你为什么得到同样的结果呢?它有点欺骗性,但它不一样.当您尝试访问时schoolclasses
,Laravel将检查它是否已被急切加载.如果是这样,它将返回该集合schoolclasses
.没有查询.它只是立即返回它们.但是,如果您没有急于加载它们,Laravel将在现场查询数据库并获取schoolclasses
.最终,对于这个特定的例子,你会得到相同的结果,但是当你查询数据库时会有所不同.
然而,这实际上是热切加载的主要好处的一个不好的例子.
预先加载的主要好处是缓解N + 1查询问题.假设您想要获得5所学校及其所有课程.如果没有急切的加载,这就是你要做的:
$schools = School::take(5)->get(); foreach ($schools as $school) { $schoolclasses = $school->schoolclasses; }
对于这样一个简单的任务,总共有6个查询.我在下面添加了评论,以了解查询的来源:
$schools = School::take(5)->get(); // First query foreach ($schools as $school) { // For each school, you are querying the database again to get its related classes. // 5 schools = 5 more queries $schoolclasses = $school->schoolclasses; }
但是,如果您急于加载所有内容,则只有两个查询:
// Two queries here that fetches everything $schools = School::with('schoolclasses')->take(5)->get(); foreach ($schools as $school) { // No more queries are done to get the classes because // they have already been eager loaded $schoolclasses = $school->schoolclasses; }