Eager Loading, de oplossing voor het bekende N+1 probleem.

Voordat ik überhaupt bij de term “Eager Loading” terecht kom, is het goed om vooraf een stukje uitleg te geven over hoe een website, of in mijn geval maatwerk web applicatie werkt. Vrijwel iedere website bevat dynamische content, voor een gewone bedrijfswebsite gaat dit vaak niet veel verder dan b.v. de teksten voor op de pagina’s, de menu titels, de volgorde van het menu, locaties naar afbeeldingen etc. Deze gegevens worden opgeslagen in een database, en iedere database bestaat weer uit meerdere tabellen.

Stel nu dat je website een blog bevat, een blog kan veelal worden voorzien van reacties, en dus kun je dat vertalen naar een database structuur.

  • Blog
    Een blog tabel bevat in ieder geval de titel, inhoud, datum, en het ID van de gekoppelde gebruiker.
  • Reactie
    Een reactie tabel bevat het unieke ID van de blog waaraan deze gekoppeld wordt, zo weet de database bij welk blog artikel de reactie hoort. Daarnaast is er natuurlijk de reactie zelf, datum van plaatsing, en het ID van de gebruiker die de reactie heeft geplaatst.

In het geval van bovenstaande structuur, kunnen we dus spreken van een zogenaamde one-to-many relatie, want een blog heeft of kan meerdere reacties hebben. Indien ik nu al mijn blog artikelen wil ophalen, zeg ik middels een query tegen de database “haal voor mij alle velden op uit de tabel blog”.

Zo gezegd zo gedaan, de database geeft mij een mooie lijst terug met al mijn blog artikelen, vervolgens kan ik op mijn website een lusje uitvoeren die 1 voor 1 door mijn lijst heen gaat en het blog artikel weergeeft. Maar ik had ook nog reacties op mijn blog artikelen, en die wil ik ook graag weergeven, dit betekend dat ik nu voor iedere keer dat hij door de lus heen gaat, een extra query moet uitvoeren die deze reacties uit de database haalt.

Indien mijn website slechts 10 blogs heeft merk ik hier weinig van, maar wat nu wanneer ik 1.000.000 blog artikelen heb verzameld. Het ophalen van de blog artikelen zelf neemt slechts 1 query in beslag, maar dit betekend tevens dat mijn lus 1.000.000 keer zal worden doorlopen, en dat er 1.000.000 keer een extra query zal worden uitgevoerd om de reacties op te halen, het zogenaamde N+1 probleem.

Dit is exact het probleem dat “Eager Loading” tegengaat, want in plaats van nu 1.000.001 query’s uit te voeren wordt dit gereduceerd tot slechts 2 query’s.

De eerste haalt alle blog artikelen op, net zoals hij altijd al deed, de nieuwe echter zegt tegen de database, haal voor mij alle reacties op, welke gekoppeld is aan één van de zojuist opgehaalde blog ID’s.

Vertaald naar query’s krijg je dan iets als:

SELECT * FROM `blogs`

Deze query zegt letterlijk, selecteer alles (*) uit de tabel blogs.

SELECT * FROM `comments` WHERE blog_id IN (1, 2, 3, 4, 5, 6, …)

Deze query zegt letterlijk, selecteer alles (*) uit de tabel comments waar het blog_id 1, 2, 3, 4, 5 of 6 is.

Vervolgens kun je in PHP de resultaten groeperen per blog artikel. Al met al een reductie van maar liefst 999.999 query’s, niet slecht toch?

 

Peter Venema
Qlic

Terug naar overzicht