Technisch artikel
Database-indexen kiezen op basis van echte Laravel-query’s
Onderbouw een samengestelde index met filters, sortering en uitvoeringsplannen. Controleer ook schrijfkosten en correcte resultaten.
- SQL
- MySQL
- Laravel

In dit artikel
Kies een index voor een concrete filter-, sorteer- en joincombinatie. Een index op iedere kolom kan writes en opslag duurder maken zonder de belangrijke query te helpen. Het queryplan en representatieve data bepalen of de afweging werkt.
Voorbeeldquery: een organisatie zoekt haar open dossiers, gesorteerd op aanmaakdatum. Onderzoek een samengestelde index op de organisatie, status en datum, maar toets de gekozen volgorde met de werkelijk gebruikte database en verdeling van statussen. Dit voorbeeld beweert geen gemeten versnelling.
- Leg databaseversie, rijaantal, verdeling, query en parameters vast.
- Vergelijk plan en herhaalde looptijden met dezelfde koude of warme cacheconditie.
- Meet ook inserts, updates en indexgrootte; verwijder geen index zonder gebruik en rollback te controleren.
Begin bij één concrete lijstquery
Neem een orderoverzicht dat binnen één account open bestellingen toont, begrensd tot een datumbereik en gesorteerd op datum en ID. Dit is een illustratief domeinmodel, niet een bestaande tabel of klantcase uit Codegenie. Leg eerst de echte SQL, bindings, databaseversie, bestaande indexen en verdeling van waarden vast. Het aantal bestellingen per account en het aandeel open orders bepalen mede hoeveel werk een toegangspad vraagt.
use App\Models\Order;
// Example only: the Order model and these columns belong to your application.
// Resolve accountId through your application's authorisation rules.
// Resolve from/to in the same time zone as the stored created_at values.
$orders = Order::query()
->select(['id', 'account_id', 'status', 'created_at'])
->where('account_id', $accountId)
->where('status', 'open')
->where('created_at', '>=', $from)
->where('created_at', '<', $to)
->orderByDesc('created_at')
->orderByDesc('id')
->limit(50)
->get();Kies de kolomvolgorde vanuit het toegangspatroon
Een kandidaat is (account_id, status, created_at, id). De twee gelijkheidsfilters staan vóór het datumbereik en de sortering. Dit is geen regel dat de meest selectieve kolom altijd eerst moet. Een MySQL-index kan via zijn linkerprefix bruikbaar zijn voor andere querypatronen, maar het ontbreken van een voorste filter kan een andere toegang noodzakelijk maken. Beoordeel de hele workload voordat je een bestaande index vervangt. InnoDB neemt primaire-sleutelkolommen bovendien op in secundaire indexrecords; beoordeel daarom of id expliciet nodig is en welke volgorde het plan werkelijk gebruikt.
Lees het plan vóór en na één wijziging
-- MySQL 8.4 example for a disposable test copy with an orders table.
-- Never execute index DDL blindly on production. Review existing indexes first.
-- Keep the SQL, parameter values and data identical between comparisons.
EXPLAIN FORMAT=TRADITIONAL
SELECT id, account_id, status, created_at
FROM orders
WHERE account_id = 42 AND status = 'open'
AND created_at >= '2026-09-01 00:00:00'
AND created_at < '2026-09-02 00:00:00'
ORDER BY created_at DESC, id DESC
LIMIT 50;
-- Candidate only; obtain approval and assess write/storage costs separately.
CREATE INDEX orders_account_status_created_id
ON orders (account_id, status, created_at, id);
EXPLAIN FORMAT=TRADITIONAL
SELECT id, account_id, status, created_at
FROM orders
WHERE account_id = 42 AND status = 'open'
AND created_at >= '2026-09-01 00:00:00'
AND created_at < '2026-09-02 00:00:00'
ORDER BY created_at DESC, id DESC
LIMIT 50;Controleer key, type, rows, filtered en Extra in de traditionele EXPLAIN-uitvoer. Dit zijn planinformatie en schattingen, geen gemeten responstijd. Een tabelscan kan bij weinig rijen de juiste keuze zijn. Ook filesort is niet automatisch een fout. Vergelijk welke rijen worden gelezen en gesorteerd, in plaats van alleen te controleren of de nieuwe indexnaam verschijnt. EXPLAIN ANALYZE voert de SELECT werkelijk uit en hoort alleen thuis in een geschikte, gecontroleerde omgeving.
Controleer datums, paginering en correcte resultaten
Het halfopen interval bevat de start en sluit de volgende dag uit. Bepaal de grenzen in de tijdzone van de gegevens; een lokale kalenderdag is bij een uurwisseling niet altijd 24 uur. Vergelijk dezelfde ID’s, volgorde en waarden vóór en na. Test lege resultaten, gelijke tijdstippen en grote accounts. De extra ID-sortering maakt gelijke datums voorspelbaar. Bij paginate() kan een afzonderlijke COUNT-query bestaan: een snelle lijstquery bewijst niet dat ook de telling snel is.
Controleer meer dan alleen een snellere SELECT
Meet herhaaldelijk met dezelfde data, parameters en duidelijk beschreven cachecondities. Controleer naast selecties ook inserts, updates, schijfruimte en het effect op andere querypatronen. Bepaal vooraf welke afwijking aanleiding geeft tot terugdraaien en beoordeel mogelijke locks bij het aanmaken of verwijderen van een index. De voorbeeldcode is geen migratiebestand voor productie. Het resultaat van deze analyse kan ook zijn dat een voorgestelde index niet nodig is of dat de applicatie eerst minder query’s moet uitvoeren.
Verder onderzoeken
Een queryplan is één deel van de diagnose. Hieronder vind je aanvullende uitleg en een afgebakende SQL-dienst. De demonstraties gebruiken fictieve gegevens, niet de resultaten van een klantproject. Deel bij een aanvraag alleen een probleembeschrijving en geanonimiseerde context; geen wachtwoorden, volledige dumps of persoonsgegevens.
Laatst bijgewerkt:


