Joh*_*nyQ 1 php laravel laravel-5.1
我有这个结构:
学校 - > hasMany - > Classes
所以当我尝试下面的代码时 artisan tinker
App\School::with('schoolclasses')->find(2283)->schoolclasses;
Run Code Online (Sandbox Code Playgroud)
我可以毫无问题地获得课程.
但是当我尝试没有使用时,我仍然可以得到相同的结果而没有问题:
App\School::find(2283)->schoolclasses;
Run Code Online (Sandbox Code Playgroud)
是否Eloquent急于加载?如果是这样,如何禁用它?
不,Laravel默认情况下并不急于加载.让我们一步一步来.让我们->schoolclasses;暂时忽略.
App\School::with('schoolclasses')->find(2283);
Run Code Online (Sandbox Code Playgroud)
这将两次查询数据库.首先,它将获得School2283的主键.然后,它将立即查询数据库并获得所有相关的schoolclasses.
App\School::find(2283);
Run Code Online (Sandbox Code Playgroud)
这只会查询一次数据库.它只会得到School.到目前为止还没有急切的加载.如果您调试并跟踪数据库查询,您将看到这只会查询数据库一次,而急切加载将查询它两次.
当您尝试访问该schoolclasses做->schoolclasses;,一切实际工作.那你为什么得到同样的结果呢?它有点欺骗性,但它不一样.当您尝试访问时schoolclasses,Laravel将检查它是否已被急切加载.如果是这样,它将返回该集合schoolclasses.没有查询.它只是立即返回它们.但是,如果您没有急于加载它们,Laravel将在现场查询数据库并获取schoolclasses.最终,对于这个特定的例子,你会得到相同的结果,但是当你查询数据库时会有所不同.
然而,这实际上是热切加载的主要好处的一个不好的例子.
预先加载的主要好处是缓解N + 1查询问题.假设您想要获得5所学校及其所有课程.如果没有急切的加载,这就是你要做的:
$schools = School::take(5)->get();
foreach ($schools as $school)
{
$schoolclasses = $school->schoolclasses;
}
Run Code Online (Sandbox Code Playgroud)
对于这样一个简单的任务,总共有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;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果您急于加载所有内容,则只有两个查询:
// 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;
}
Run Code Online (Sandbox Code Playgroud)