Zeg je “Database” of “Data” dan heb je vast wel eens van SQL gehoord. Als business data-analist, data-engineer of uberhaupt als data-gedreven professional, schrijf je waarschijnlijk al regelmatig SQL queries.
Geen ervaring met SQL maar wil je wel snel de basics leren? Zelfs in het AI-tijdperk blijft SQL belangrijk. Volg daarom een cursus op Datacamp, of gebruik de SQL Cheat-sheet als je wel eens met SQL gewerkt hebt maar het even kwijt bent.
Maar het schrijven van écht goede SQL queries is een vak apart. Vaak schrijf je de query voor een analyse, een dashboard, een rapportage of als onderdeel van een ander datamodel of data product. Hierbij staat het eindresultaat centraal en denk je wellicht niet altijd aan de manier hoe de query is geschreven.
In eerste instantie merk je daar vaak nog weinig van. Maar naarmate de hoeveelheid data groeit, of hoevaak je de query per tijdsinterval draait, kan een inefficiënte query ineens minuten duren, onnodig veel I/O gebruiken of een dashboard vertragen.
Maar je hoeft geen database administrator of query optimizer-expert te zijn om betere SQL te schrijven.
Met een aantal bewuste keuzes tijdens het schrijven van je query kun je al veel verschil maken.
Hieronder vind je 10 praktische do’s & don’ts voor betere SQL query performance.
Geen zin om de hele blog te lezen? Check hier de 10 do’s en don’ts netjes onder elkaar. Dan kun jij weer verder om je backlog weg te werken:
| ⛔ Don’ts! ⁉️ | ✅ Do’s 👌 |
| 1. Gebruik niet standaard de SELECT * | 1. Selecteer alleen de kolommen die je nodig hebt |
| 2. WHERE-statement te laat of verkeerd gebruiken | 2. Beperk je dataset zo veel mogelijk |
| 3. DISTINCT gebruiken zonder te weten waarom | 3. Onderzoek waar je duplicaten vandaan komen |
| 4. JOIN tabellen ff voor de ‘zekerheid’ | 4. JOIN alleen data die je nodig hebt |
| 5. Negeren hoeveel records je query produceert | 5. Controleer je records tijdens het bouwen |
| 6. Steeds hetzelfde opnieuw berekenen | 6. Hergebruik je logica bewust |
| 7. Meer data aggregeren dan je nodig hebt | 7. Denk na over het detailniveau van je analyse |
| 8. Schrijven van filters die onnodig moeilijk te optimaliseren zijn | 8. Houd rekening met ‘sargability’ |
| 9. Beoordeel je performance alleen op een kleine testquery | 9. Denk na over de schaal waarop je SQL uiteindelijk zal draaien |
| 10. Optimaliseer op je gevoel | 10. Meet en kijk naar het execution plan |
1. Don’t: gebruik niet standaard de SELECT *
Do: selecteer alleen de kolommen die je nodig hebt
We zien het vaak:
SELECT *
FROM orders;
Maar heb je werkelijk alle kolommen nodig?
Als je analyse uiteindelijk alleen order_id, customer_id en order_date gebruikt, selecteer dan ook alleen die kolommen:
SELECT
order_id,
customer_id,
order_date
FROM orders;
Vooral bij brede tabellen en grote datasets kan het voorkomen dat onnodig veel data wordt gelezen en verwerkt. Zonde!
Het sterretje betekent eigenlijk: ‘neem alles mee wat je tegenkomt’. Om je query goed te laten presteren is het nodig om alleen hetgeen te pakken wat je nodig hebt. Des te specifieker je te werk gaat, des te beter.
Het gebruik van SELECT * is natuurlijk niet verboden. Er zijn gevallen waarin dit wel kan:
- Ad hoc analyses
- Kijken hoe de data eruit ziet
SELECT *van een CTE (Common Table Expression) waarin je zeker weet dat je alleen die kolommen nodig hebt
Het kost wat meer tijd, maar het maakt de leesbaarheid voor jou en de optimizer stukken beter!
Tip! Als je toch een SELECT * gebruikt, plak dan bijvoorbeeld een Limit 500 aan het einde van je query. Zo neem je alleen de eerste 500 resultaten mee in je analyse.
Kortom: vraag niet meer data op dan je nodig hebt.
2. Don’t: WHERE-statement te laat of verkeerd gebruiken
Do: beperk je dataset zo veel mogelijk
Hiermee zorg je ervoor dat de computing costs onnodig hoog zijn.
Stel dat je een analyse maakt over Nederlandse klanten in 2026. Dan heb je waarschijnlijk niet alle klanten en alle transacties uit de volledige historie nodig.
Afhankelijk van welke database-engine je gebruikt, doet de optimizer dit zelf al en probeert deze eerst zo efficiënt mogelijk bij de data te komen die je nodig hebt. Maar dit blijft toch een belangrijk aandachtspuntje.
Wanneer de kolom in de WHERE-statement geen index bevat, zal de engine veel of alle rijen moeten controleren om de voorwaarde te bepalen. Wanneer de kolom wel een geschikte index bevat, kan dit de zoekactie versnellen.
Neem als voorbeeld een boek, stel dat je alle hoofdstukken wilt lezen die met de letter K beginnen. Dan ga je naar index achterin, zoekt naar de letter K en negeer je alles wat niet onder de K staat. Dat is inderdaad lekker snel lezen zo.
Maar, stel dat we alle hoofdstukken vervangen met het aantal letters in de titel, dan is de index niet meer toe rijkend omdat deze niet meer overeen komt met wat er in de index staat. De optimizer denkt ook zo. Met een bewerking van de index kolom komt deze te vervallen
DO:
WHERE country = 'NL'
AND order_date >= '2026-01-01'
AND order_date < '2027-01-01'
DON’T:
WHERE country = 'NL'
AND YEAR(order_date) = 2026
Hier kan de index op order_date minder effectief worden gebruikt, afhankelijk van de database-engine en uitvoering.
Hetzelfde principe geldt bijvoorbeeld voor berekeningen in een filter:
DO:
WHERE prijs > korting + 100
DON’T:
WHERE prijs - 100 > korting
Ook hier kan een bewerking op de kolom ervoor zorgen dat een beschikbare index minder goed gebruikt kan worden.
Dit is geen vrijbrief om overal een index op te plaatsen. Dat werkt namelijk ook averechts. Maak alleen een index op een kolom als deze frequent wordt gebruikt om te filteren of te joinen en als deze past bij het gebruikspatroon van je database.
Gebruik je filters dus bewust. Hoe minder irrelevante data uiteindelijk verwerkt hoeft te worden, hoe beter.
Je hoeft SQL niet kunstmatig ingewikkeld te maken om ieder filter letterlijk zo vroeg mogelijk te schrijven. Moderne database-optimizers kunnen zelf veel optimalisaties uitvoeren.
Werk met de kleinste dataset die nodig is om je vraag te beantwoorden.
3. Don’t: DISTINCT gebruiken zonder te weten waarom
Do: onderzoek waar je duplicaten vandaan komen
Een veelvoorkomende situatie:
Je schrijft een query, voert een paar JOINs uit en ineens heb je dubbele records.
De snelle oplossing?
SELECT DISTINCT ...
De duplicaten zijn verdwenen.
Maar het probleem misschien niet…
DISTINCT kan een relatief dure operatie zijn, omdat de database de resultaten moet vergelijken om dubbele rijen te verwijderen. Als het even niet hoeft, zou ik deze vermijden. Maar soms is het natuurlijk wel benodigd.
Als je last hebt van duplicaten, dien je eerst te onderzoeken waarom je duplicaten hebt en of dit terecht is.
Controleer eerst je JOINs goed en kijk daarna of er in de bron tabel, of de gejoinde tabellen, unieke sleutels of primary keys aanwezig zijn die al afdwingen dat alle rijen uniek zijn.
Een DISTINCT is dan waarschijnlijk overbodig.
Onverwachte duplicaten? Controleer eerst je JOINs.
4. Don’t: JOIN tabellen ff voor de ‘zekerheid’
Do: JOIN alleen data die je nodig hebt
In analytische queries ontstaan soms lange ketens van JOINs.
Deze joins kunnen snel het aantal rijen en kolommen verveelvoudigen. Ook hier is het noodzaak om alleen hetgeen te joinen wat je nodig hebt.
Een JOIN kan bovendien onderdeel zijn van je filtering. Kijk dus niet alleen naar wat je uiteindelijk selecteert, maar ook naar waar je al kunt beperken.
Bijvoorbeeld:
SELECT
k.naam,
b.status
FROM klanten k
LEFT JOIN bestellingen b
ON k.id = b.klant_id
WHERE b.status = 'Verzonden'
Door de WHERE-voorwaarde op de rechtertabel verandert het resultaat van deze LEFT JOIN in de praktijk naar een situatie waarin alleen klanten met een match met status Verzonden overblijven.
Je kunt deze filtering ook in de JOIN opnemen:
SELECT
k.naam,
b.status
FROM klanten k
LEFT JOIN bestellingen b
ON k.id = b.klant_id
AND b.status = 'Verzonden'
Door de filtering in de JOIN op te nemen, kan de database in bepaalde situaties efficiënter omgaan met de hoeveelheid data die vanuit de join wordt meegenomen. Hoe groot het performanceverschil is, hangt af van de database-engine en het execution plan.
Iedere JOIN voegt werk toe en kan bovendien het aantal records in je dataset veranderen.
Vraag jezelf daarom bij iedere JOIN af:
Welke informatie haal ik uit deze tabel en heb ik die informatie nodig voor mijn eindresultaat?
5. Don’t: Negeren hoeveel records je query produceert
Do: controleer je records tijdens het bouwen
Een simpele maar effectieve gewoonte: controleer tijdens het ontwikkelen hoeveel records je hebt.
Stel:
Je begint met 2 miljoen orders. Na de eerste JOIN heb je 2 miljoen records, na de tweede JOIN heb je 2,1 miljoen en na de derde JOIN ineens 35 miljoen.
Dan wil je waarschijnlijk eerst begrijpen wat daar gebeurt voordat je nog vijf CTE’s toevoegt.
Controleer na iedere JOIN, CTE of andere belangrijke stap de row count tijdens het ontwikkelen of tweaken van je query.
Hiermee bevestig je dat je niet een onnodig aantal records verwekt.
Check bijvoorbeeld:
SELECT COUNT(*)
Of:
SELECT COUNT(DISTINCT order_id)
Of:
SELECT COUNT(*)
...
GROUP BY ...
Het verschil tussen deze aantallen kan veel vertellen over wat er in je query gebeurt.
Performanceproblemen worden regelmatig veroorzaakt doordat ergens halverwege een query veel meer data ontstaat dan de analist verwacht.
Mocht je met een JOIN heel veel onnodige records toevoegen, dan gebruik je capaciteit terwijl je dit niet nodig hebt.
Controleer dus niet alleen het eindresultaat. Kijk ook wat er onderweg met je data gebeurt.
6. Don’t: Steeds hetzelfde opnieuw berekenen
Do: hergebruik je logica bewust
Analytische SQL bevat vaak berekeningen, aggregaties en transformaties.
Wanneer dezelfde complexe berekening op verschillende plekken terugkomt, is het verstandig om te onderzoeken of je die logica kunt centraliseren.
CTE’s zijn je vriend als het gaat om leesbaarheid en het structureren van je query.
Met CTE’s kun je ervoor zorgen dat complexe berekeningen of andere lastige SELECT-statements alleen worden uitgevoerd op het aantal records dat daadwerkelijk benodigd is.
Stel dat je een grote tabel hebt waarin je alleen van een bepaalde groep een SUM wilt hebben. Bereken de SUM van deze groep apart in een CTE en join deze wanneer je dit veld nodig hebt.
Stel dat customer_type = 1 zo’n 10% van je dataset is. Dan hoef je de berekening niet onnodig over de overige 90% uit te voeren.
CTE’s kunnen bijvoorbeeld helpen om een query overzichtelijker te maken:
WITH customer_revenue AS (
SELECT
customer_id,
SUM(revenue) AS total_revenue
FROM orders
WHERE customer_type = 1
GROUP BY customer_id
)
SELECT ...
FROM orders o
LEFT JOIN customer_revenue c
ON o.id = c.id;
Maar ook hier geldt: een CTE is niet automatisch sneller.
Verschillende database-engines gaan verschillend om met CTE’s, subqueries en materialisatie. Test dit daarom stap voor stap om te kijken of dit daadwerkelijk performancewinst oplevert.
Gebruik CTE’s daarom in eerste instantie om je logica helder te structureren en controleer bij performanceproblemen hoe jouw platform de query daadwerkelijk uitvoert.
Leesbaarheid is goed. Hergebruik is goed. Maar meten blijft belangrijk.
7. Don’t: Meer data aggregeren dan je nodig hebt
Do: denk na over het detailniveau van je analyse
GROUP BY, COUNT, SUM, window functions en andere analytische functies zijn enorm krachtig.
Maar deze functies kunnen al snel duur worden.
Stel dat je uiteindelijk alleen omzet per maand nodig hebt. Vraag jezelf dan af of alle onderliggende detailrecords gedurende de volledige query nodig blijven.
Hetzelfde geldt voor window functions zoals:
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY order_date DESC
)
Op een kleine dataset is dat nauwelijks merkbaar.
Op honderden miljoenen records kan sorteren en partitioneren een aanzienlijke operatie worden.
Gebruik analytische functies dus vooral bewust en op zo min mogelijk data.
Denk niet alleen na over welke berekening je nodig hebt, maar ook over hoeveel data die berekening moet verwerken.
8. Don’t: schrijven van filters die onnodig moeilijk te optimaliseren zijn
Do: houd rekening met ‘sargability’
Dit punt is eerder benoemd in deze blog en ik behandel het nog een keer.
Je kunt schrijven:
WHERE YEAR(order_date) = 2026
Maar afhankelijk van de database kan dat minder efficiënt zijn dan:
WHERE order_date >= '2026-01-01'
AND order_date < '2027-01-01'
De tweede variant kan de database in bepaalde situaties beter in staat stellen om beschikbare indexes, partitions of andere optimalisaties te gebruiken.
Dit principe heet sargability.
Simpel gezegd: schrijf je voorwaarden zo dat de database bestaande indexen en andere optimalisaties zo goed mogelijk kan benutten.
Dit geldt niet alleen voor WHERE-statements, maar ook voor JOINs.
Als de kolom waarop gejoined wordt geïndexeerd is en in de ON-clause van de JOIN wordt deze kolom getransformeerd, kan ook hier de index minder effectief worden gebruikt.
Als data-analist of dataspecialist hoef je niet iedere interne werking van de database te kennen.
Het is wel nuttig om te beseffen dat de manier waarop je een filter formuleert invloed kan hebben op de uitvoering ervan.
Een functioneel juiste query is niet automatisch een optimaal uitgevoerde query.
9. Don’t: beoordeel je performance alleen op een kleine testquery
Do: denk na over de schaal waarop je SQL uiteindelijk zal draaien
Tijdens het ontwikkelen werk je misschien met:
LIMIT 100
De query is binnen een seconde klaar.
Mooi.
Maar dat is niet per definitie representatief voor de hele dataset.
In productie draait dezelfde logica misschien over vijf jaar aan data en honderden miljoenen records. Of een dashboard voert de query tientallen keren per dag uit voor verschillende gebruikers.
Een query die één keer vijf seconden duurt, lijkt misschien acceptabel.
Een query die vijf seconden duurt en 10.000 keer per dag wordt uitgevoerd, is een ander verhaal.
Denk daarom bij query performance niet alleen aan je huidige test, maar ook aan:
- datavolume;
- frequentie;
- aantal gebruikers;
- groei van de dataset;
- compute- en cloudkosten.
Performance gaat ook over schaal.
10. Don’t: optimaliseer op je gevoel
Do: meet en kijk naar het execution plan
Meten is weten, ook met query performance.
Je hebt het idee dat iets niet goed is, dus je herschrijft een CTE.
Geen verschil.
Je verandert een JOIN.
Nog steeds langzaam.
Je verwijdert een DISTINCT.
Een klein beetje sneller.
Dit is query tuning op basis van trial-and-error.
Wanneer een query daadwerkelijk performanceproblemen veroorzaakt, probeer dan eerst te achterhalen waar het probleem zit. Hak je code eventueel in stukken en kijk waar de grote vertragingen ontstaan.
Veel databases en datawarehouses bieden daarvoor een execution plan, query profile of vergelijkbare analysefunctionaliteit.
Daarmee kun je bijvoorbeeld zien:
- hoeveel records worden verwerkt;
- welke onderdelen veel tijd kosten;
- waar grote hoeveelheden data ontstaan;
- welke
JOIN-strategieën worden gebruikt; - hoeveel data wordt gescand;
- waar sorting of aggregatie plaatsvindt.
Je hoeft niet direct ieder onderdeel van een execution plan te kunnen verklaren.
Zo verander je SQL optimization van gokken in analyseren.
Meet eerst waar het probleem zit voordat je de query gaat herschrijven.
Goede query performance begint tijdens het schrijven
Query performance is niet alleen de verantwoordelijkheid van database administrators, data engineers of het onderliggende dataplatform.
Ook als data-analist of dataspecialist heb je invloed.
Iedere keer dat je SQL schrijft, maak je keuzes over hoeveel data je ophaalt, welke tabellen je combineert, wanneer je aggregeert en hoe complex je berekeningen worden.
SQL query performance optimaliseren begint daarom niet pas wanneer een dashboard traag wordt of een query minutenlang blijft draaien.
Het begint bij het schrijven van de query.
De belangrijkste vraag is uiteindelijk simpel:
Hoeveel data moet ik daadwerkelijk verwerken om mijn vraag te beantwoorden?
Door bewust om te gaan met SELECT, WHERE, JOIN, DISTINCT, aggregaties, CTE’s en execution plans kun je vaak al veel winst behalen.
En misschien nog belangrijker: je leert niet alleen snellere SQL schrijven, maar ook beter begrijpen waarom een query goed of slecht presteert.
Mocht je uiteindelijk nog steeds tegen performance issues aanlopen, kunnen wij je verder helpen als interim of freelance Data Engineer en Datawarehouse expert.
Veelgestelde vragen over SQL query performance
Hoe kan ik SQL query performance optimaliseren?
Begin met het beperken van de hoeveelheid data die je query verwerkt. Selecteer alleen de kolommen die je nodig hebt, filter je dataset bewust, controleer je JOINs en voorkom onnodige aggregaties en DISTINCT-operaties.
Kijk vervolgens naar de schaal waarop de query draait en gebruik een execution plan of query profile om te bepalen waar de daadwerkelijke bottleneck zit.
Kort gezegd: verwerk zo weinig mogelijk data en meet waar de query tijd en capaciteit gebruikt.
Waarom is SELECT * slecht voor SQL performance?
SELECT * is niet per definitie slecht, maar zorgt ervoor dat alle kolommen worden opgevraagd. Bij brede tabellen en grote datasets kan hierdoor meer data worden gelezen en verwerkt dan noodzakelijk.
Als je maar drie kolommen nodig hebt, is het daarom beter om deze drie kolommen expliciet te selecteren.
Dat is bovendien duidelijker voor degene die de query later moet onderhouden.
Wanneer moet ik SQL query performance optimaliseren?
Niet pas wanneer een query daadwerkelijk traag wordt.
Bij kleine datasets kunnen inefficiënties nauwelijks merkbaar zijn. Naarmate datasets groeien, dashboards vaker worden geraadpleegd en meer gebruikers dezelfde queries uitvoeren, kunnen kleine inefficiënties grote gevolgen hebben voor performance en compute- of cloudkosten.
Daarom is het verstandig om bij het schrijven van SQL al rekening te houden met schaal.
Wat is sargability in SQL?
Sargability betekent in de context van SQL dat een voorwaarde zo is geschreven dat de database een beschikbare index of andere optimalisatie zo effectief mogelijk kan gebruiken.
Een eenvoudig voorbeeld is:
WHERE order_date >= '2026-01-01'
AND order_date < '2027-01-01'
in plaats van:
WHERE YEAR(order_date) = 2026
De exacte uitvoering verschilt per database-engine, maar het principe is belangrijk: de manier waarop je een filter schrijft kan invloed hebben op SQL performance.
Hoe kan ik een SQL query sneller maken?
Er is geen standaard oplossing om iedere SQL query sneller te maken. Begin daarom met meten.
Controleer onder andere:
- hoeveel records worden verwerkt;
- hoeveel data wordt gescand;
- welke
JOINs worden uitgevoerd; - waar aggregaties plaatsvinden;
- of er onnodige duplicaten ontstaan;
- welke onderdelen van de query de meeste tijd kosten.
Gebruik hiervoor waar mogelijk het execution plan of query profile van jouw database of datawarehouse.
Zijn CTE’s sneller dan subqueries?
Niet automatisch.
CTE’s zijn vooral nuttig om complexe SQL-logica overzichtelijk te structureren en logica te hergebruiken. Verschillende database-engines kunnen CTE’s, subqueries en materialisatie anders verwerken.
Gebruik CTE’s daarom niet alleen omdat je verwacht dat ze sneller zijn.
Test de query en bekijk hoe jouw database-engine deze daadwerkelijk uitvoert.
Waarom maakt een JOIN mijn SQL query langzaam?
Een JOIN voegt werk toe en kan het aantal records in je resultaat sterk vergroten.
Een veelvoorkomende oorzaak van performanceproblemen is dat een JOIN meer records produceert dan verwacht. Bijvoorbeeld doordat de relatie tussen twee tabellen niet één-op-één is.
Controleer daarom tijdens het bouwen van je query hoeveel records je vóór en na iedere JOIN hebt.
Krijg je ineens 35 miljoen records waar je er 2 miljoen verwachtte? Dan zit daar waarschijnlijk iets interessants.
Kan SPECTS helpen met SQL performance en data engineering?
Jazeker! Dat is een groot deel van ons vak. Wij helpen opdrachtgevers met uitdagingen en professionals om door te groeien tot Senior Data Engineers. Mocht je dus ondanks deze tips nog steeds tegen performance problemen aanlopen, dan kunnen wij je zeker verder helpen.
Bij SPECTS Data Partners helpen we organisaties met data engineering, datamodellen, dashboards en het slimmer benutten van data. Al onze collega’s zijn in loondienst en werken volgens een Midlance-model maar dan speciaal getweakt voor Consultancy & Datagedreven interim opdrachten.
Benieuwd waar in jouw dataomgeving de performanceproblemen ontstaan? Neem contact met ons op voor een vrijblijvende kennismaking!








