eduardweb.
PostgreSQLIntermediar#performance#postgresql#database#jsonb#indexing

Când folosești JSONB în Postgres și cum îl indexezi cu GIN fără să îți îngropi baza

De Mihai Popescu, 24 iul. 2026 · 5 vizualizări · 2 like-uri

Postat 24 iul. 2026
sql
-- 1. Creează indexul optimizat pentru căutări de conținere
CREATE INDEX idx_products_attributes_path
ON products USING gin (attributes jsonb_path_ops);

-- 2. Query greșit (NU folosește indexul GIN de mai sus, face Seq Scan):
-- SELECT * FROM products WHERE attributes->>'color' = 'red';

-- 3. Query corect și rapid (utilizează jsonb_path_ops și scade la sub 10ms):
SELECT id, name, attributes
FROM products
WHERE attributes @> '{"color": "red", "brand": "Logitech"}';

Am văzut prea multe schemuri de Postgres distruse doar pentru că echipa n-a avut chef să scrie o migrare și a trântit o coloană data jsonb. JSONB e un instrument excelent, dar dacă îl folosești ca pe un substitut pentru un model relațional bine gândit, o să ajungi rapid la probleme grave de performanță.

M-am lovit de asta direct acum doi ani, la un magazin online cu peste 120.000 de produse unde specificațiile tehnice erau complet haotice: televizoarele aveau diagonală și rezoluție, hainele aveau mărime și material, iar anvelopele aveau indici de viteză.

Când are sens JSONB și când e o capcană

Regula mea e simplă: dacă datele au o structură dinamică, necunoscută în faza de design sau specifică doar pentru 1-2% din rânduri, JSONB e rege. Atribute dinamice de produs, payload-uri de webhook-uri externe, sau setări per utilizator care se schimbă des ca structură.

Dar dacă ai un câmp pe care îl folosești în JOIN-uri, pe care ai FK-uri, sau peste care faci WHERE la fiecare request principal, mută-l în coloană clasică. Coloanele normale consumă mai puțin spațiu, au statistici mult mai bune în query planner și permit constrângeri reale la nivel de DB.

Operatorii @> și ->> și de ce contează pentru indecși

Dacă vrei să cauți eficient în JSONB, trebuie să înțelegi cum procesează Postgres operațiile. Cel mai des văd cod de genul:

SELECT * FROM products WHERE attributes->>'color' = 'red';

Un coleg din echipă se plângea că un query similar dura 450ms pe 100k de rânduri. De ce? Pentru că ->> extrage valoarea ca text, iar un index GIN standard pe coloană nu va fi folosit pentru așa ceva fără o expresie dedicată.

Săbiuța de aur pentru JSONB este operatorul de conținere @>. Acesta verifică dacă documentul JSON din stânga include structura din dreapta.

Indexarea GIN – secretul jsonb_path_ops

Dacă pui un index GIN simplu (CREATE INDEX ON products USING gin (attributes)), Postgres va indexa fiecare cheie și valoare din document. E util dacă faci interogări complexe pe chei necunoscute, dar indexul devine uriaș.

În 90% din cazuri, vrei doar să cauți valori pentru chei cunoscute. Aici intervenim cu opțiunea jsonb_path_ops.

Optimizarea asta ne-a coborât timpul de execuție de la 450ms la doar 8ms. Indexul jsonb_path_ops folosește hash-uri pentru căile complete, ocupă aproape jumătate din spațiul unui GIN standard și e sesizabil mai rapid la citire.

Trade-off-ul dureros: Write Amplification

Toată lumea laudă JSONB pentru flexibilitate, dar puțini vorbesc despre costul la scriere. În Postgres, un document JSONB e imutabil. Dacă ai un JSONB de 30KB și faci un UPDATE să modifici un singur boolean din el, Postgres nu schimbă acel bit – scrie un rând complet nou cu toți cei 30KB.

La proiectul de e-commerce de care ziceam, aveam un job care făcea update la stocuri într-un JSONB o dată la 5 minute. Ne-a umflat baza de date cu bloat masiv și I/O-ul pe disk era constant peste 90%. Am mutat stocul într-o coloană INTEGER separată și am lăsat în JSONB doar atributele statice.

Voi cum folosiți JSONB în producție? Îl țineți doar pentru metadata strictă sau aveți baze întregi schemaless?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.