Laravel Blog

Tutorial, tips, consigli e patemi su Laravel & dintorni

Eager Loading in Laravel

Nel refactoring e nella trasformazione in packaging del CMS sviluppato in Laravel nel corso dell’ultimo anno sono incappato nei primi pezzi di codice non ottimizzati.

Che sono anche occasione per fare un punto e cercare di stabilire, dopo mesi di lavoro con Laravel, pro e contro delle singole funzionalità. O meglio, quando è conveniente utilizzare gli “helpers” che Laravel offre e quando no. Uno di questi “helper” è l’Eager Loading ovvero la possibilità di risolvere in maniera “smart” il problema delle query N+1.

Nello specifico abbiamo il seguente modello WarpEmail

warpemail-php.sh

	public function language()
    {
        return $this->belongsTo("Warp\Core\Language");
    } 

E il seguente Controller

warpemailcontroller.sh

$warpemails = WarpEmail::all(); //old way

$warpemails = WarpEmail::with('language')->get(); // eager loading

In questo modo vengono generate soltanto due query quando provo a scorrere WarpEmail

query.sh

select * from `email`
select * from `language` where `language`.`deleted_at` is null and `language`.`id` in ('2', '1', '4')

Invece delle N (inteso come singole query sul Modello Language) + 1 (inteso come modello principale WarpEmail). Nel mio caso quindi 13.

query.sh

select * from `email`
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '2' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '1' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '1' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '2' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '2' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '2' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '2' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '4' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '4' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '2' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '4' limit 1
select * from `language` where `language`.`deleted_at` is null and `language`.`id` = '4' limit 1

A parte che bisognerebbe ottimizzare i select per prelevare soltanto i campi che ci interessano nei casi più complessi preferisco ancora usare i vecchi Join (ORM e quindi Eloquent) piuttosto che l’Eager Loading (che utilizza Query Builder e quindi Fluent).

E’ questione di abitudine (e quindi di velocità ed efficienza) oltre che del risparmio di una query.

Rispondi

%d blogger cliccano Mi Piace per questo: