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

Postgres JSONB: Când merită să renunți la tabelele clasice și cum pui index GIN ca să nu plângi la interogări

De Ioana Marinescu, 27 mai 2026 · 5 vizualizări · 3 like-uri

Postat 27 mai 2026
sql
-- Crearea tabelei cu un câmp JSONB
CREATE TABLE produse (
    id SERIAL PRIMARY KEY,
    nume VARCHAR(255) NOT NULL,
    specificatii JSONB
);

-- Crearea unui index GIN optimizat folosind jsonb_path_ops
CREATE INDEX idx_produse_specificatii ON produse USING gin (specificatii jsonb_path_ops);

-- Query eficient care utilizează indexul GIN creat mai sus
SELECT nume, specificatii
FROM produse
WHERE specificatii @> '{"atribute": {"ram": "16GB", "tip": "DDR5"}}';

Am văzut des extrema asta în producție. Fie oameni care normalizează tabelele până ajung să facă 15 JOIN-uri pentru un amărât de profil de utilizator, fie developeri care aruncă totul într-un singur câmp JSONB și pretind că folosesc Postgres ca pe un MongoDB mai rapid. Ambele abordări dor la scară.

JSONB în Postgres este o unealtă superbă, dar vine cu un cost pe care mulți îl ignoră până când baza de date începe să gâfâie în producție. Am pățit asta pe un proiect de e-commerce unde aveam specificații tehnice extrem de variate pentru produse. Pantofii au mărimi și culori, laptopurile au RAM și procesoare. Să faci tabele clasice pentru fiecare variație e rețeta perfectă pentru burnout administrativ.

Când e JSONB o idee excelentă și care sunt compromisurile?

Regula mea de aur este simplă: folosește JSONB doar pentru date polimorfe sau atribute dinamice care nu participă direct în relații de tip Foreign Key. Dacă ai nevoie de constrângeri de integritate referențială, mergi pe coloane clasice. Nu vrei să te trezești scriind triggeri complecși doar ca să validezi că un ID dintr-un JSON chiar există în altă tabelă.

Un alt trade-off major este legat de modificări. Postgres folosește MVCC (Multi-Version Concurrency Control). Asta înseamnă că atunci când faci update la o singură cheie dintr-un document JSONB de 50KB, Postgres nu modifică doar acea cheie. El scrie o copie complet nouă a întregului rând pe disc. La un volum mare de scrieri (write amplification), performanța la scriere va scădea dramatic.

Salvarea vine de la indexul GIN

Dacă lași un câmp JSONB neindexat și ai peste 100k înregistrări, orice căutare în interiorul lui va genera un full table scan. Serverul tău va începe să fiarbă. Pentru a rezolva asta, folosim un index GIN (Generalized Inverted Index).

Există două moduri principale de a defini un index GIN în Postgres:

  1. jsonb_ops (cel default): Indexează absolut tot — fiecare cheie, valoare și sub-cheie. Este extrem de flexibil, dar ocupă foarte mult spațiu pe disc și în memorie.
  2. jsonb_path_ops: Indexează doar rutele complete (de tip cheie-valoare). Este mult mai mic, uneori și cu 50% mai compact decât cel default, și considerabil mai rapid la interogări. Dezavantajul? Nu te ajută dacă vrei să verifici doar dacă o anumită cheie există în document, fără să-i pese de valoare.

În exemplul de mai jos, am definit structura pe care am folosit-o noi în producție, optimizată special pentru căutări rapide folosind operatorul @> (care verifică dacă un JSON conține un alt JSON).

Cum scrii query-ul ca să activezi indexul?

Este crucial să folosești operatorii potriviți. Dacă scrii un query folosind operatorul ->> pentru a extrage text și apoi îl compari clasic, Postgres s-ar putea să ignore complet indexul GIN dacă nu l-ai definit specific pe acea expresie. Cel mai sigur mod de a profita de un index GIN general este operatorul de incluziune @>.

După ce am aplicat indexul jsonb_path_ops pe tabela noastră, timpul de răspuns pentru filtrarea produselor după specificații tehnice a scăzut instant. Am coborât de la query-uri care durau secunde bune la interogări care se executau în doar 12-15 milisecunde.

Voi cum gestionați datele astea dinamice? Mergeți pe tabele clasice de tip EAV sau aruncați totul într-un JSONB și lăsați indexul GIN să facă magia?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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