Ontwikkelaars stellen me vaak dezelfde vraag: "Mijn API is traag. Waar begin ik?" De reflex is meestal om de server te upgraden of het RAM-geheugen te verdubbelen. Dat kost geld en lost de kernoorzaak zelden op. In de meeste Laravel-applicaties ligt de bottleneck in de database-laag. De elegante syntaxis van het framework maakt het gemakkelijk om te vergeten dat elke Eloquent-aanroep uiteindelijk SQL wordt, en dat SQL vaak de plek is waar de problemen beginnen.
Voordat je een serverinstelling aanpast, loop je methodisch door je queries heen.
Begin met de juiste diagnostiek
Optimaliseer niet in het duister. Het willekeurig herschrijven van queries is giswerk, en giswerk kost uren aan tijd.
Je moet de statements vinden die de meeste totale tijd in beslag nemen. Monitor je applicatie onder een echte belasting. Laravel Telescope geeft je een helder overzicht van elke uitgevoerde query tijdens een request, inclusief de uitvoeringstijd. Laravel Debugbar toont deze in je browser tijdens lokale ontwikkeling, zodat je afwijkingen direct kunt opmerken. Wanneer je problemen in productie wilt opsporen, schakel dan de MySQL Slow Query Log in. Deze legt statements vast die een door jou gedefinieerde drempelwaarde overschrijden, wat het ideaal maakt voor het vinden van verrassingen die niet zichtbaar zijn in kleine datasets. Als je grotere systemen draait, kan een Application Performance Monitoring-tool trage HTTP-endpoints correleren met specifieke database-aanroepen.
Terwijl je de gegevens beoordeelt, moet je op twee dingen letten: de absolute uitvoeringstijd en de frequentie van de aanroepen. Een query die veertig milliseconden duurt, klinkt onschuldig totdat je beseft dat deze tweeduizend keer per minuut wordt uitgevoerd. Een rapport dat drie seconden duurt maar slechts één keer per uur wordt gedraaid, is misschien minder belangrijk dan een zoekopdracht van een halve seconde die op elke pagina wordt uitgevoerd. Los eerst de problemen met de grootste impact op.
Stop met het opvragen van alles
SELECT * is handig. Het is ook duur. Wanneer je Model::all() schrijft of een resultaatset ophaalt zonder kolommen te benoemen, haalt MySQL elk veld op voor elke overeenkomende rij. Dat omvat grote tekstvelden, JSON-blobs en alles wat nog meer op de tabel staat. De resultaatset wordt groter, het geheugengebruik stijgt en de tijd die nodig is voor het serialiseren van de response neemt toe.
Wees expliciet. Als je controller alleen de velden id, name en email nodig heeft, vraag dan precies die op:
User::select('id', 'name', 'email')->get();
In de query builder geldt hetzelfde principe. Kleinere payloads verplaatsen zich sneller over het netwerk en verbruiken minder RAM op je applicatieserver. Dit is een van de makkelijkste verbeteringen die er zijn, maar het wordt vaak overgeslagen omdat Laravel SELECT * als standaardgedrag hanteert.
Laat EXPLAIN je wijzigingen leiden
Refactor nooit een trage query zonder eerst EXPLAIN uit te voeren. In MySQL toont het trefwoord EXPLAIN het query-uitvoeringsplan. Het laat precies zien hoe de optimizer van plan is om je gegevens te vinden.
Let op de kolom type. Als je ALL ziet, voert MySQL een volledige tabelscan uit. Dat betekent dat elke rij wordt gelezen om aan je WHERE-clausule te voldoen. Kijk naar de kolom key om te zien of de optimizer überhaupt een index gebruikt. Controleer vervolgens de kolom Extra. Als je Using temporary of Using filesort ziet, bouwt MySQL tussenliggende tabellen of vindt er sortering in het geheugen plaats omdat je huidige structuur de query niet efficiënt kan verwerken.
Voer EXPLAIN uit in je MySQL-client, of gebruik een tool die de output voor je formatteert. Zodra je het plan ziet, weet je of het probleem een ontbrekende index is, een slechte join, of een predicaat dat de engine niet kan optimaliseren. Gissen is niet langer nodig.
Indexeer met een doel
Indexes zijn het krachtigste hulpmiddel om zoekopdrachten te versnellen, maar ze werken alleen als ze aansluiten bij de manier waarop je query's schrijft. Zonder de juiste index scant MySQL rij voor rij. Dat kan prima aanvoelen tijdens de ontwikkeling op een tabel met duizend rijen, maar kan volledig vastlopen in productie op een tabel met tien miljoen rijen.
Begin met single-column indexes voor velden die vaak voorkomen in WHERE-clausules. Als je constant filtert op status, voeg dan een index toe op status.
Wanneer een query op meerdere kolommen tegelijk filtert, kun je overstappen op composite indexes. De volgorde van de kolommen in de index is belangrijk, omdat MySQL composite indexes van links naar rechts leest. Dit wordt de "leftmost prefix rule" genoemd. Als je query zoekt op user_id en vervolgens sorteert op created_at, helpt een composite index op (user_id, created_at) aanzienlijk. Draai de volgorde om en de optimizer gebruikt de index mogelijk helemaal niet voor de filter.
Indexeer niet elke kolom. Elke index zorgt voor extra overhead bij inserts, updates en deletes, omdat MySQL de structuur moet bijhouden. Voeg ze doelbewust toe op basis van de patronen die je tijdens het meten hebt gevonden.
Houd functies weg van kolommen
Deze fout schakelt ongemerkt indexen uit. Wanneer je een kolom in een functie plaatst binnen een WHERE-clausule, kan MySQL niet
