JSONB-operators en containmentqueries
Gebruik de containment- en path-operators die GIN-indexen daadwerkelijk kunnen versnellen.
JSONB-operators en containmentqueries is een gratis Prestaties en queryoptimalisatie in PostgreSQL-les op CoddyKit. Dit is les 1 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Prestaties en queryoptimalisatie in PostgreSQL. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Prestaties en queryoptimalisatie in PostgreSQL bevat in totaal 4 lessen.
Waarom de keuze van de operator bepaalt of een index wordt gebruikt
In PostgreSQL kun je een kolom van het type jsonb op veel verschillende manieren doorzoeken, maar niet elke operator kan een index gebruiken. De prestaties hangen hier vrijwel volledig af van het kiezen van operators die een GIN-index kan versnellen.
- Een GIN-index (Generalized Inverted Index) slaat de sleutels en waarden in je JSON-documenten op, zodat zoekopdrachten de volledige tabel kunnen overslaan.
- De twee belangrijkste operators zijn insluiting (
@>) en aanwezigheid van sleutels (?,?|,?&).
In deze les leer je precies welke operators dat zijn en hoe je query's schrijft die geschikt blijven voor indexgebruik.
De insluitingsoperator @>
De insluitingsoperator @> vraagt: bevat de linker JSONB de rechter JSONB? De rechterkant is een fragment en Postgres controleert of elke sleutel/waarde daarin voorkomt in het linker document.
'{"a":1,"b":2}' @> '{"a":1}'is true.'{"a":1}' @> '{"a":1,"b":2}'is false (de rechterkant bevat meer).
Dit is het belangrijkste hulpmiddel voor het filteren van rijen: WHERE data @> '{"status":"active"}' vindt elke rij waarvan de JSON dat paar bevat.
SELECT '{"a":1,"b":2}'::jsonb @> '{"a":1}'::jsonb AS contains_a,
'{"a":1}'::jsonb @> '{"a":1,"b":2}'::jsonb AS contains_both;Een GIN-index maken voor insluiting
Een gewone GIN-index op een jsonb-kolom ondersteunt zowel insluitingsoperators als operators voor de aanwezigheid van sleutels. Dit is de index die je als eerste kiest.
- De standaardoperator class
jsonb_opsindexeert elke sleutel en waarde. - Deze versnelt
@>,?,?|en?&.
Maak de index één keer aan; daarna worden insluitingsfilters die eerder de hele tabel doorzochten bitmap-indexscans.
CREATE INDEX idx_events_data
ON events
USING GIN (data);Insluitingsfilters in WHERE
Zodra de GIN-index bestaat, schrijf je de filter als een insluitingscontrole, zodat de planner deze kan gebruiken. Het vergelijken van een genest fragment werkt ook, omdat insluiting recursief is.
- Vergelijking op het hoogste niveau:
data @> '{"status":"active"}'. - Geneste vergelijking:
data @> '{"user":{"plan":"pro"}}'.
Let erop dat we rechts een letterlijke JSON objectwaarde doorgeven, geen kolomverwijzing of functieaanroep. Die vorm van de letterlijke waarde maakt de query geschikt voor indexgebruik.
SELECT id, created_at
FROM events
WHERE data @> '{"user":{"plan":"pro"}}'
ORDER BY created_at DESC
LIMIT 50;Operators voor aanwezigheid van sleutels ? ?| ?&
Soms wil je alleen weten of een sleutel aanwezig is, ongeacht de waarde ervan. De aanwezigheidsoperators handelen dit af en worden ook door GIN versneld.
data ? 'email'— true als de sleutelemailop het hoogste niveau bestaat.data ?| array['phone','email']— true als een van beide sleutels bestaat.data ?& array['phone','email']— true als alle sleutels bestaan.
Belangrijk: ? controleert alleen sleutels op het hoogste niveau en controleert bij arrays of de tekenreeks een element is.
SELECT '{"email":"x@y.z","phone":"123"}'::jsonb ? 'email' AS has_email,
'{"email":"x@y.z"}'::jsonb ?| array['phone','email'] AS has_any,
'{"email":"x@y.z"}'::jsonb ?& array['phone','email'] AS has_all;De valkuil: padextractie-operators -> en ->>
De extractie-operators lijken handig, maar worden niet versneld door een standaard-GIN-index:
data -> 'status'retourneert de waarde alsjsonb.data ->> 'status'retourneert de waarde alstext.
Een query zoals WHERE data ->> 'status' = 'active' dwingt een sequentiële scan af op een gewone GIN-index, omdat de index geen vergelijkingen met geëxtraheerde scalairen indexeert. Gebruik in plaats daarvan bij voorkeur de insluitingsvorm data @> '{"status":"active"}'.
-- Slow on a plain GIN index (seq scan):
SELECT * FROM events WHERE data ->> 'status' = 'active';
-- Fast equivalent (uses GIN):
SELECT * FROM events WHERE data @> '{"status":"active"}';->> redden met een expressie-index
Als je echt bereik- of patroonvergelijkingen op één veld nodig hebt, is een B-tree-expressie-index op de geëxtraheerde tekst het juiste hulpmiddel — niet GIN.
- Indexeer precies de expressie die je bevraagt.
- Daarna kunnen vergelijkingen zoals
=,<,>enBETWEENdeze gebruiken.
De expressie van de query moet teken voor teken overeenkomen met de geïndexeerde expressie, anders negeert de planner de index.
CREATE INDEX idx_events_status
ON events ((data ->> 'status'));
-- Now this can use the B-tree index:
SELECT * FROM events WHERE (data ->> 'status') = 'active';jsonb_path_ops: kleiner, sneller, alleen voor insluiting
De alternatieve operator class jsonb_path_ops indexeert gehashte paden van wortel naar blad in plaats van elke sleutel.
- Dit levert een kleinere index op die doorgaans sneller is voor
@>-query's. - Nadeel: deze ondersteunt alleen insluiting (
@>), niet de aanwezigheidsoperators?,?|en?&.
Kies jsonb_path_ops wanneer je werklast voornamelijk uit insluitingsfilters bestaat en je nooit zoekopdrachten naar aanwezige sleutels nodig hebt.
CREATE INDEX idx_events_data_path
ON events
USING GIN (data jsonb_path_ops);Insluiting tegen arrays
Insluiting werkt ook binnen JSON-arrays, waardoor dit ideaal is voor gegevens met tags. Als je wilt vragen "bevat deze array een waarde?", plaats je de waarde rechts in een array.
'["a","b","c"]' @> '["b"]'is true.- Voor een getagd document vindt
data @> '{"tags":["urgent"]}'rijen waarvan de arraytagsde waardeurgentbevat.
Dit blijft volledig geschikt voor indexgebruik met een GIN-index, zodat filteren op tags goed schaalbaar is.
SELECT '["a","b","c"]'::jsonb @> '["b"]'::jsonb AS has_b,
'{"tags":["urgent","billing"]}'::jsonb
@> '{"tags":["urgent"]}'::jsonb AS is_urgent;Controleren met EXPLAIN
Neem nooit zomaar aan dat de index wordt gebruikt — controleer dit. Voer EXPLAIN uit en zoek naar een Bitmap Index Scan op je GIN-index. Een Seq Scan betekent dat je operator of expressie de index onbruikbaar heeft gemaakt.
- Goed teken:
Bitmap Index Scan on idx_events_data. - Slecht teken:
Seq Scan on eventsmet een JSON-filter.
Gebruik EXPLAIN (ANALYZE, BUFFERS) om ook de werkelijke tijd en het aantal gelezen pagina's te bekijken.
EXPLAIN (ANALYZE, BUFFERS)
SELECT id FROM events
WHERE data @> '{"status":"active"}';Alles samenbrengen: een beslisregel
Gebruik deze snelle regel bij het schrijven van een JSONB-filter:
- Een sleutel/waarde of genest fragment vergelijken? Gebruik
@>met een GIN-index. - Alleen controleren of een sleutel aanwezig is? Gebruik
?/?|/?&met de standaardklassejsonb_opsvan GIN. - Alleen insluitingen als werklast en de kleinst mogelijke index gewenst? Gebruik GIN met
jsonb_path_ops. - Een bereik of patroon op één scalair veld? Gebruik een B-tree-expressie-index op
->>.
Vermijd gelijkheidsfilters met ->> zonder een overeenkomende expressie-index — ze veroorzaken sequentiële scans.
Snelle controle
Je hebt een standaard-GIN-index van jsonb_ops op events.data. Welke WHERE-component kan die index gebruiken?
Samenvatting
Je hebt geleerd welke JSONB-operators daadwerkelijk voordeel hebben van indexering:
- @> (insluiting) is de belangrijkste door GIN versnelde filter, ook voor geneste objecten en arrays.
- ?, ?| en ?& (aanwezigheid van sleutels) worden door GIN versneld, maar alleen met de standaardklasse
jsonb_ops, en controleren sleutels op het hoogste niveau. - jsonb_path_ops levert een kleinere, snellere index die alleen voor insluiting geschikt is.
- Extractiefilters met -> en ->> gebruiken GEEN gewone GIN-index; herschrijf ze als
@>of voeg een B-tree-expressie-index toe. - Controleer altijd met
EXPLAINof je een Bitmap Index Scan krijgt en geen Seq Scan.
Leer SQL met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 22
- Lessen
- 88
Veelgestelde vragen
Is de les “JSONB-operators en containmentqueries” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad Prestaties en queryoptimalisatie in PostgreSQL, waaronder “JSONB-operators en containmentqueries”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus Prestaties en queryoptimalisatie in PostgreSQL bevat in totaal 4 lessen.
Wat leer ik in “JSONB-operators en containmentqueries”?
Gebruik de containment- en path-operators die GIN-indexen daadwerkelijk kunnen versnellen. Je oefent met Prestaties en queryoptimalisatie in PostgreSQL door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Prestaties en queryoptimalisatie in PostgreSQL te beginnen?
Ervaring vooraf is niet nodig. Prestaties en queryoptimalisatie in PostgreSQL op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 1 van 4.
Hoe lang duurt de les “JSONB-operators en containmentqueries”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Prestaties en queryoptimalisatie in PostgreSQL?
Ja. Elke les over Prestaties en queryoptimalisatie in PostgreSQL bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- JSONB-operators en containmentqueries
- GIN- versus expression-indexen op JSONB
- JSONB bevragen met JSONPath
- Wanneer u JSONB moet normaliseren