JSONB-operatorer og containment-spørringer
Bruk containment- og path-operatorene som GIN-indekser faktisk kan akselerere.
JSONB-operatorer og containment-spørringer er en gratis leksjon i Ytelse og spørringsoptimalisering i PostgreSQL på CoddyKit. Dette er leksjon 1 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Ytelse og spørringsoptimalisering i PostgreSQL, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Ytelse og spørringsoptimalisering i PostgreSQL inneholder totalt 4 leksjoner.
Hvorfor valg av operator avgjør om indeksen brukes
I PostgreSQL kan en kolonne av typen jsonb søkes på mange forskjellige måter, men ikke alle operatorer kan bruke en indeks. Ytelsen handler nesten utelukkende om å velge operatorer som en GIN-indeks kan akselerere.
- En GIN-indeks (Generalized Inverted Index) lagrer nøklene og verdiene i JSON-dokumentene, slik at oppslag kan hoppe over hele tabellen.
- De to viktigste operatorene er inneslutning (
@>) og nøkkeleksistens (?,?|,?&).
Denne leksjonen lærer Dem nøyaktig hvilke operatorer dette er, og hvordan De skriver spørringer som er indeksvennlige.
Inneslutningsoperatoren @>
Inneslutningsoperatoren @> spør: inneholder venstre JSONB høyre JSONB? Høyresiden er et fragment, og Postgres kontrollerer at hver nøkkel/verdi i fragmentet finnes i dokumentet til venstre.
'{"a":1,"b":2}' @> '{"a":1}'er true.'{"a":1}' @> '{"a":1,"b":2}'er false (høyresiden inneholder mer).
Dette er arbeidshesten for filtrering av rader: WHERE data @> '{"status":"active"}' finner alle rader der JSON-en inneholder dette paret.
SELECT '{"a":1,"b":2}'::jsonb @> '{"a":1}'::jsonb AS contains_a,
'{"a":1}'::jsonb @> '{"a":1,"b":2}'::jsonb AS contains_both;Opprette en GIN-indeks for inneslutning
En vanlig GIN-indeks på en jsonb-kolonne støtter både inneslutningsoperatorer og operatorer for nøkkeleksistens. Dette er indeksen De bør prøve først.
- Den standardiserte operator-klassen
jsonb_opsindekserer hver nøkkel og verdi. - Den akselererer
@>,?,?|og?&.
Opprett den én gang, så blir inneslutningsfiltre som tidligere skannet hele tabellen, til punktgrafikkindeksskanninger.
CREATE INDEX idx_events_data
ON events
USING GIN (data);Inneslutningsfiltre i WHERE
Når GIN-indeksen finnes, skriver De filteret som en inneslutningskontroll slik at planleggeren kan bruke den. Det fungerer også å matche et nøstet fragment, fordi inneslutning er rekursiv.
- Treff på øverste nivå:
data @> '{"status":"active"}'. - Nøstet treff:
data @> '{"user":{"plan":"pro"}}'.
Legg merke til at De sender et JSON-objektliteral på høyresiden, ikke en kolonnereferanse eller et funksjonskall. Det er denne literalformen som gjør spørringen egnet for indeksbruk.
SELECT id, created_at
FROM events
WHERE data @> '{"user":{"plan":"pro"}}'
ORDER BY created_at DESC
LIMIT 50;Operatorer for nøkkeleksistens ? ?| ?&
Noen ganger er De bare opptatt av om en nøkkel finnes, uavhengig av verdien. Eksistensoperatorene håndterer dette og akselereres også av GIN.
data ? 'email'– true hvis nøkkelenemailfinnes på øverste nivå.data ?| array['phone','email']– true hvis minst én av disse nøklene finnes.data ?& array['phone','email']– true hvis alle disse nøklene finnes.
Viktig: ? kontrollerer bare nøkler på øverste nivå, og for tabeller kontrollerer den om strengen er et element.
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;Fellen: baneuttrekksoperatorene -> og ->>
Uttrekksoperatorene ser praktiske ut, men akselereres ikke av en standard GIN-indeks:
data -> 'status'returnerer verdien somjsonb.data ->> 'status'returnerer verdien somtext.
En spørring som WHERE data ->> 'status' = 'active' tvinger frem en sekvensiell skanning med en vanlig GIN-indeks, fordi indeksen ikke indekserer sammenligninger av uttrukne skalarer. Foretrekk i stedet inneslutningsformen 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"}';Redde ->> med en uttrykksindeks
Hvis De faktisk trenger område- eller mønstersammenligninger på ett felt, er en B-tre-uttrykksindeks på den uttrukne teksten det riktige verktøyet – ikke GIN.
- Indekser nøyaktig uttrykket De spør etter.
- Da kan sammenligninger som
=,<,>ogBETWEENbruke den.
Spørringens uttrykk må samsvare med det indekserte uttrykket tegn for tegn, ellers ignorerer planleggeren indeksen.
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: mindre, raskere, bare for inneslutning
Den alternative operator-klassen jsonb_path_ops indekserer hashede baner fra rot til blad i stedet for hver enkelt nøkkel.
- Den gir en mindre indeks og er vanligvis raskere for
@>-spørringer. - Avveiningen er at den støtter bare inneslutning (
@>), ikke eksistensoperatorene?,?|og?&.
Velg jsonb_path_ops når arbeidsmengden Deres hovedsakelig består av inneslutningsfiltrering, og De aldri trenger søk etter nøkkeleksistens.
CREATE INDEX idx_events_data_path
ON events
USING GIN (data jsonb_path_ops);Inneslutning mot tabeller
Inneslutning fungerer også inne i JSON-tabeller, noe som gjør den ideell for data med tagger. For å spørre «inneholder denne tabellen en verdi?» pakker De verdien inn i en tabell på høyresiden.
'["a","b","c"]' @> '["b"]'er true.- For et dokument med tagger:
data @> '{"tags":["urgent"]}'finner rader dertags-tabellen inneholderurgent.
Dette er fullt ut egnet for indeksbruk med en GIN-indeks, slik at filtrering på tagger skalerer godt.
SELECT '["a","b","c"]'::jsonb @> '["b"]'::jsonb AS has_b,
'{"tags":["urgent","billing"]}'::jsonb
@> '{"tags":["urgent"]}'::jsonb AS is_urgent;Bekrefte med EXPLAIN
Ikke anta at indeksen brukes – bekreft det. Kjør EXPLAIN og se etter en Bitmap Index Scan på GIN-indeksen. En Seq Scan betyr at operatoren eller uttrykket hindret indeksbruk.
- Godt tegn:
Bitmap Index Scan on idx_events_data. - Dårlig tegn:
Seq Scan on eventsmed et JSON-filter.
Bruk EXPLAIN (ANALYZE, BUFFERS) for også å se faktisk tidsbruk og hvor mange sider som ble lest.
EXPLAIN (ANALYZE, BUFFERS)
SELECT id FROM events
WHERE data @> '{"status":"active"}';Slik henger det sammen: en beslutningsregel
Bruk denne enkle regelen når De skriver et JSONB-filter:
- Treff på nøkkel/verdi eller et nøstet fragment? Bruk
@>med en GIN-indeks. - Kontrollerer De bare om en nøkkel finnes? Bruk
?/?|/?&med standardklassenjsonb_opsi GIN. - Arbeidsmengde som bare bruker inneslutning, og ønske om minst mulig indeks? Bruk
jsonb_path_opsi GIN. - Område eller mønster på ett skalarfelt? Bruk en B-tre-uttrykksindeks på
->>.
Unngå likhetsfiltre med ->> uten en tilsvarende uttrykksindeks – de utløser sekvensielle skanninger.
Hurtigsjekk
De har en standard GIN-indeks med jsonb_ops på events.data. Hvilken WHERE-betingelse kan bruke denne indeksen?
Oppsummering
De har lært hvilke JSONB-operatorer som faktisk drar nytte av indeksering:
- @> (inneslutning) er det primære GIN-akselererte filteret, også for nøstede objekter og tabeller.
- ?, ?| og ?& (nøkkeleksistens) akselereres av GIN, men bare med standardklassen
jsonb_ops, og de kontrollerer nøkler på øverste nivå. - jsonb_path_ops gir en mindre og raskere indeks som bare støtter inneslutning.
- -> og ->>-filtre for uttrekking bruker IKKE en vanlig GIN-indeks; skriv dem om til
@>, eller legg til en B-tre-uttrykksindeks. - Bekreft alltid med
EXPLAINat De får en Bitmap Index Scan, ikke en Seq Scan.
Lær deg SQL med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 22
- Leksjoner
- 88
Ofte stilte spørsmål
Er leksjonen «JSONB-operatorer og containment-spørringer» gratis?
Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Ytelse og spørringsoptimalisering i PostgreSQL, inkludert «JSONB-operatorer og containment-spørringer», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Ytelse og spørringsoptimalisering i PostgreSQL inneholder totalt 4 leksjoner.
Hva lærer jeg i «JSONB-operatorer og containment-spørringer»?
Bruk containment- og path-operatorene som GIN-indekser faktisk kan akselerere. Du øver på Ytelse og spørringsoptimalisering i PostgreSQL med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med Ytelse og spørringsoptimalisering i PostgreSQL?
Ingen tidligere erfaring er nødvendig. Ytelse og spørringsoptimalisering i PostgreSQL på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.
Hvor lang tid tar leksjonen «JSONB-operatorer og containment-spørringer»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne Ytelse og spørringsoptimalisering i PostgreSQL-leksjonen?
Ja. Alle Ytelse og spørringsoptimalisering i PostgreSQL-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- JSONB-operatorer og containment-spørringer
- GIN- kontra uttrykksindekser på JSONB
- Spørre JSONB med JSONPath
- Når JSONB bør normaliseres ut