eduardweb.
PostgreSQLIntermediar#performance#postgresql#database#indexing

Când merită să pui JSONB în Postgres și cum îl strunești cu indecși GIN

De Bogdan Răducanu, 5 iul. 2026 · 11 vizualizări · 3 like-uri

Postat 5 iul. 2026
sql
-- Creăm tabelul de utilizatori cu setări flexibile
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    preferences JSONB NOT NULL DEFAULT '{}'::jsonb
);

-- Creăm un index GIN optimizat pentru căutări de tip "conține"
CREATE INDEX idx_users_preferences ON users USING gin (preferences jsonb_path_ops);

-- Query care folosește indexul (operatorul @> înseamnă "conține")
SELECT id, email 
FROM users 
WHERE preferences @> '{"theme": "dark", "notifications": {"email": true}}';

Văd tot mai des tendința de a folosi Postgres pe post de MongoDB, trântind coloane de tip jsonb pentru orice structură care pare puțin flexibilă. E o capcană în care am picat și eu acum câțiva ani și care m-a costat câteva nopți de debug când baza de date a început să gâfâie. Hai să vedem unde își are sensul JSONB și unde îți tragi singur un glonț în picior.

Când e pe bune util JSONB (Și când e doar lene)

La un proiect trecut cu vreo 15k de utilizatori activi, aveam de salvat setările de interfață ale fiecăruia: temă, limba preferată, widget-urile din dashboard și ordinea lor. Dacă făceam tabele relaționale clasice pentru asta, aveam o structură de join-uri de plângeam în pumni la fiecare query de login. Aici JSONB a fost perfect.

Regula mea de aur e simplă: dacă ai date pe care doar le citești și le scrii ca pe un bloc unitar, fără să ai nevoie de constrângeri de integritate referențială pe proprietățile din interior, JSONB e rege.

În schimb, dacă ajungi să faci JOIN-uri simulate pe chei din interiorul JSON-ului sau dacă ai nevoie de validări stricte (de exemplu, un câmp trebuie să fie neapărat un ID valid din alt tabel), treci înapoi la tabele clasice. Altfel, o să ai date corupte în producție și nicio metodă simplă de a le curăța.

Trade-off-ul ascuns: JSON vs JSONB

Multă lume confundă json cu jsonb. Tipul json salvează textul exact așa cum îl trimiți. E rapid la scriere, dar groaznic la citire pentru că Postgres trebuie să parseze string-ul ăla la fiecare interogare.

jsonb parsează JSON-ul la scriere și îl salvează într-un format binar descompus. Asta înseamnă că scrierea e puțin mai lentă (cam cu 15-20% în testele mele), dar citirea și căutările sunt extrem de rapide. În plus, elimină spațiile goale inutile și cheile duplicate.

Cum faci interogările să zboare cu indecși GIN

Dacă ai o tabelă mare și cauți în interiorul JSONB-ului fără index, Postgres va face un "sequential scan" de toată frumusețea. La un milion de rânduri, serverul tău o să înceapă să transpire.

Aici intervine indexul GIN (Generalized Inverted Index). Acesta indexează practic toate cheile și valorile din interiorul structurii.

Există două moduri mari de a crea un index GIN:

  1. Cel implicit (jsonb_ops) - indexează tot (chei, valori, sub-obiecte). E flexibil, dar ocupă mult spațiu pe disc.
  2. Cel optimizat (jsonb_path_ops) - indexează doar perechile cheie-valoare. E mult mai mic și mai rapid, dar nu te lasă să cauți doar dacă o anumită cheie există, ci doar dacă se potrivește o structură întreagă.

La un volum de date măricel, un index GIN bine pus ne-a scăzut timpul de răspuns la search de la 1.2 secunde la doar 8 milisecunde. Merită efortul, dar folosiți-l cu cap. Voi în ce proiecte ați regretat că ați folosit JSONB în loc de coloane clasice?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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