Ytelse og spørringsoptimalisering i PostgreSQL · leksjon

GIN- kontra uttrykksindekser på JSONB

Velg mellom GIN-indekser med jsonb_path_ops og målrettede uttrykksindekser ut fra spørringsformene Deres.

Leksjon 2 av 413 trinn

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:

  • -> returnerer jsonb.
  • ->> returnerer text – 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.

Gratis å komme i gang

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

  1. JSONB-operatorer og containment-spørringer
  2. GIN- kontra uttrykksindekser på JSONB
  3. Spørre JSONB med JSONPath
  4. Når JSONB bør normaliseres ut
← Tilbake til Ytelse og spørringsoptimalisering i PostgreSQL