GIN- kontra uttrykksindekser på JSONB
Velg mellom GIN-indekser med jsonb_path_ops og målrettede uttrykksindekser ut fra spørringsformene Deres.
GIN- kontra uttrykksindekser på JSONB er en gratis leksjon i Ytelse og spørringsoptimalisering i PostgreSQL på CoddyKit. Dette er leksjon 2 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.
To måter å indeksere JSONB på
Når De lagrer data i en jsonb-kolonne, tvinger en uindeksert spørring PostgreSQL til å lese og tolke hver rad. Det finnes to svært forskjellige verktøy for å løse dette:
- GIN-indeks – en generell invertert indeks over hele dokumentet, utmerket for fleksible oppslag på inneslutning og nøkkel/verdi.
- Uttrykksindeks (B-tre) – en målrettet indeks på én uttrukket skalar, utmerket for en bestemt og kjent spørringsform.
Denne leksjonen handler om å velge riktig indeks for Deres spørringsmønstre.
Eksempeltabellen
Se for Dem en events-tabell der hver rad inneholder en fleksibel JSON-nyttelast. Vi skal indeksere data-kolonnen.
Legg merke til at nyttelasten kombinerer noen vanlige nøkler (type, user_id) med vilkårlige tillegg.
CREATE TABLE events (
id bigserial PRIMARY KEY,
data jsonb NOT NULL
);
INSERT INTO events (data) VALUES
('{"type": "login", "user_id": 42, "ip": "10.0.0.1"}'),
('{"type": "logout", "user_id": 42}'),
('{"type": "login", "user_id": 99, "mfa": true}');Standard-GIN-indeksen: jsonb_ops
En vanlig GIN-indeks bruker standardklassen jsonb_ops. Den indekserer hver nøkkel OG hver verdi som separate oppføringer.
Dette støtter det bredeste utvalget av operatorer: inneslutning @>, nøkkeleksistens ?, ?| og ?&.
Kostnaden er at indeksen tar mer plass på disken og er tregere å bygge og oppdatere, fordi den lagrer langt flere oppføringer per rad.
CREATE INDEX idx_events_data_gin
ON events USING gin (data);
-- Supports key existence AND containment:
-- WHERE data ? 'mfa'
-- WHERE data @> '{"type":"login"}'Den slankere GIN-indeksen: jsonb_path_ops
Hvis De bare bruker inneslutningsoperatoren @> (og JSONPath-operatorene @? / @@), bør De foretrekke operator-klassen jsonb_path_ops.
- Den hasher hele nøkkel→verdi-banene til enkeltoppføringer.
- Resultatet er en merkbart mindre indeks og raskere inneslutningsoppslag.
- Avveiningen er at den IKKE støtter operatorene for nøkkeleksistens
?,?|og?&.
CREATE INDEX idx_events_data_pathops
ON events USING gin (data jsonb_path_ops);
-- Great for:
SELECT id FROM events
WHERE data @> '{"type": "login"}';Slik bruker inneslutning GIN-indeksen
Operatoren @> spør «inneholder dokumentet til venstre dokumentet til høyre?» Begge GIN-operatorklassene akselererer den.
Inneslutning er strukturell: den samsvarer med nøstede nøkler og verdier, ikke bare dem på øverste nivå. Derfor kan én GIN-indeks håndtere mange ulike filterkombinasjoner.
-- Match by one key:
SELECT * FROM events WHERE data @> '{"user_id": 42}';
-- Match by two keys at once (same index):
SELECT * FROM events
WHERE data @> '{"type": "login", "user_id": 42}';
-- Match a nested shape:
SELECT * FROM events WHERE data @> '{"flags": {"beta": true}}';Når GIN ikke strekker til: område og sortering
GIN er laget for likhetsbasert inneslutning. Den kan IKKE hjelpe med:
- Områdesammenligninger på en uttrukket verdi (
>,<,BETWEEN). - Sortering etter et JSON-felt (
ORDER BY ... LIMIT). - Prefiks- og mønstertilpasning på en tekstverdi.
For disse spørringsformene trenger De et B-tre, og for JSONB betyr det en uttrykksindeks.
-- GIN can't accelerate this range filter on an inner number:
SELECT * FROM events
WHERE (data ->> 'user_id')::int > 50
ORDER BY (data ->> 'user_id')::int
LIMIT 10;Opprette en uttrykksindeks
En uttrykksindeks lagrer resultatet av et uttrykk, ikke råkolonnen. De trekker ut én skalar fra JSON-en og indekserer den som et vanlig B-tre.
To operatorer er viktige her:
->returnererjsonb.->>returnerertext– vanligvis den typen De konverterer og indekserer.
-- B-tree on user_id extracted as an integer:
CREATE INDEX idx_events_user_id
ON events (((data ->> 'user_id')::int));
-- Now ranges, sorts and equality all use it:
SELECT * FROM events
WHERE (data ->> 'user_id')::int BETWEEN 40 AND 99
ORDER BY (data ->> 'user_id')::int;Samsvar nøyaktig med indeksuttrykket
Planleggeren bruker bare en uttrykksindeks når uttrykket i spørringen samsvarer med det indekserte uttrykket token for token, inkludert casten.
Hvis De indekserer (data ->> 'user_id')::int, men spør etter (data ->> 'user_id') som ren tekst, ignoreres indeksen.
Hold uttrekket + casten identisk overalt.
-- Indexed expression:
-- ((data ->> 'user_id')::int)
-- USES the index:
WHERE (data ->> 'user_id')::int = 42
-- IGNORES the index (text vs int mismatch):
WHERE (data ->> 'user_id') = '42'Lese EXPLAIN for å bekrefte
Ikke gjett hvilken indeks som vinner – spør planleggeren. Bruk EXPLAIN (ANALYZE, BUFFERS) og se på nodetypen:
- Bitmap Heap Scan +
Bitmap Index Scan on ...gin→ GIN-indeksen Deres håndterer containment. - Index Scan / Index Only Scan på uttrykksindeksen → B-tree-indeksen håndterer område-/sorteringsoperasjonen.
- Seq Scan → ingenting samsvarte; se på uttrykket eller operatoren på nytt.
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM events
WHERE data @> '{"type": "login"}';
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM events
WHERE (data ->> 'user_id')::int = 42;Partielle uttrykksindekser
Hvis spørringene alltid bare gjelder et delsett av radene, kan De legge til en WHERE-betingelse i indeksen. En partiell uttrykksindeks er mindre og billigere å vedlikeholde fordi den bare lagrer radene De faktisk søker i.
Her indekserer vi user_id bare for innloggingshendelser – perfekt når dette er den eneste spørringsformen som trenger den.
CREATE INDEX idx_events_login_user
ON events (((data ->> 'user_id')::int))
WHERE data @> '{"type": "login"}';Valg: en rask veiledning
Velg ut fra formen på spørringene Deres, ikke av vane:
- Fleksible filtre på mange forskjellige nøkler, eller kontroll av om en nøkkel finnes (
?) → GIN jsonb_ops. - Bare containment
@>/ JSONPath, og De ønsker en slank og rask indeks → GIN jsonb_path_ops. - Én kjent feltverdi med område, sortering eller likhet på en skalarverdi → uttrykksindeks med B-tree.
- Dette feltet brukes i spørringer mot et smalt utvalg av rader → partiell uttrykksindeks.
Det er vanlig og riktig å beholde BÅDE en GIN-indeks og én eller to uttrykksindekser på samme kolonne.
Kort kontroll
Test forståelsen Deres av valget mellom GIN og uttrykksindekser.
Oppsummering
De har lært å velge JSONB-indekser ut fra spørringsformen:
- GIN jsonb_ops — bredest operatordekning, inkludert kontroll av om en nøkkel finnes
?; størst. - GIN jsonb_path_ops — slankere og raskere, bare containment
@>og JSONPath. - Expression B-tree — én uthentet og castet skalarverdi for område, sortering og likhet; spørringsuttrykket må samsvare nøyaktig med indeksuttrykket.
- Partiell uttrykksindeks — samme idé, avgrenset til et delsett av rader for et mindre fotavtrykk.
Bekreft alltid med EXPLAIN (ANALYZE, BUFFERS), og ikke nøl med å beholde en GIN-indeks og én eller to uttrykksindekser side om side.
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 «GIN- kontra uttrykksindekser på JSONB» gratis?
Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Ytelse og spørringsoptimalisering i PostgreSQL, inkludert «GIN- kontra uttrykksindekser på JSONB», 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 «GIN- kontra uttrykksindekser på JSONB»?
Velg mellom GIN-indekser med jsonb_path_ops og målrettede uttrykksindekser ut fra spørringsformene Deres. 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 2 av 4.
Hvor lang tid tar leksjonen «GIN- kontra uttrykksindekser på JSONB»?
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