Eager loading
Learn how to optimize queries
Loading related records may cause sometimes the N + 1
query problem.
To illustrate this problem, let’s consider an Article
entity and
a User
entity.
class User extends Entity implements IMappableEntity
{
/**
* @return string
*/
public function name(): string
{
return $this->orm()->getColumn('name');
}
/**
* @return Articles[]
*/
public function articles(): array
{
return $this->orm()->getRelated('articles');
}
/**
* @inheritdoc
*/
public static function mapEntity(IEntityMapper $mapper)
{
$mapper->relation('articles')->hasMany(Article::class);
}
}
class Article extends Entity implements IMappableEntity
{
/**
* @return string
*/
public function title(): string
{
return $this->orm()->getColumn('title');
}
/**
* @return User
*/
public function author(): User
{
return $this->orm()->getRelated('author');
}
/**
* @inheritdoc
*/
public static function mapEntity(IEntityMapper $mapper)
{
$mapper->relation('author')->belongsTo(User::class);
}
}
Now, let’s query for the first 10 articles and display their title and their author’s name.
$articles = $orm(Article::class)
->orderBy('title')
->limit(10)
->all();
foreach($articles as $article) {
echo $article->title(), ' by ', $article->author()->name();
}
The above code will execute 1 query to fetch the articles, then for each of the 10 articles fetched, it will execute another query to fetch its author, resulting in a total of 11 queries executed.
We can reduce this operation to just 2 queries by using eager loading.
Specifying which relationships to be eager loaded is done with the help of the with
method.
$articles = $orm(Article::class)
->with('author')
->orderBy('title')
->limit(10)
->all();
foreach($articles as $article) {
echo $article->title(), ' by ', $article->author()->name();
}