SQL - N+1 problém (N+1 query problem)
Co je N+1 problém (N+1 query problem, N+1 performance problem, hrozba N+1). Jedná se o antipattern, kdy se při iterování provádějí další SQL dotazy, což má za následek dodatečnou zátěž na server a to pochopitelně snížuje efektivitu řešení. Zpravidla toto nastává při získávání dat z dalších vazebních tabulek (přes relační vazby).
Příklad N+1 problému
Typické pro N+1 problém je kupříkladu tato konstrukce - při iterování kategorií chceme vypsat všechny položky dané kategorie, což má za následek provedené SQL dotazu v každé iteraci.
foreach ($caregories as $category) {
// do SQL query for each category
$caretory->getItems();
}
Řešení N+1 problému
Obecně lze asi řešení N+1 problému popsat tak, že je třeba se vyvarovat konstrukcím podobným příkladu výše a snažit se relační záznamy načíst rovnou pomocí co nejmenšího počtu SQL dotazů (ideálně jednoho).
Řešení N+1 problému v Nette
V Nette za nás N+1 problém řeší databázová vrstva Explorer, kdy se rovnou položí efektivní SQL dotazy, resp. co nejméně dotazů, na všechny požadované záznamy viz dokumentace k Nette.
Řešení N+1 problému v Symfony ORM (Doctrine)
Entitě (Doctrine ORM) s vazbou OneToMany nastavíme fetch na EAGER (Eager loading) takto:
/**
* @ORM\OneToMany(targetEntity=Items::class, mappedBy="category", fetch="EAGER")
*/
private $items;
Díky tomuto načítání se rovnou načtnou i vazební data. Pokud není fetch specifikován, tak se použije default = LAZY.
Další možností je v querybuilderu použít takovouto konstrukci jak praví dokumentace k Symfony:
$this->createQueryBuilder('e')
->innerJoin('e.items', 'i')
->addSelect('i');
Touto konstrukcí se načtou rovnou i všechny vazební záznamy.