learn.chetana.fr

JSONB : le schéma flexible sans quitter le relationnel

12 min readCore

Le besoin : des attributs qu'on ne connaĂźt pas Ă  l'avance

Un catalogue produit multi-tenant : chaque client a SES attributs (matiĂšre, voltage, DLC
). Une colonne par attribut est impossible. La rĂ©ponse Postgres : une colonne JSONB — du JSON binaire, indexable et interrogeable. C'est exactement le pattern extensions du projet Ă©tudiĂ© (le nom du variant, les specs libres y vivent), et celui de cette plateforme (gardens.state).

-- interroger
SELECT * FROM variant WHERE extensions->>'marque' = 'Nike';          -- ->> = texte
SELECT * FROM variant WHERE (extensions->>'voltage')::int > 220;     -- cast si besoin
SELECT * FROM variant WHERE extensions @> '{"actif": true}';         -- @> = contient
SELECT * FROM variant WHERE extensions ? 'garantie';                 -- ? = clé existe

Indexer le JSONB (sinon Seq Scan garanti)

Un filtre sur JSONB sans index scanne toute la table. Deux stratégies :

  • index GIN sur la colonne : CREATE INDEX 
 USING gin (extensions) — accĂ©lĂšre @>, ?, ?& (les opĂ©rateurs de contenance/existence). Le couteau suisse ;
  • index B-tree sur une expression : CREATE INDEX 
 ON variant ((extensions->>'marque')) — pour un attribut prĂ©cis frĂ©quemment filtrĂ© par Ă©galitĂ©/ordre. Plus petit, plus rapide sur CE champ.

Choix : requĂȘtes variĂ©es sur le contenu → GIN ; un champ chaud identifiĂ© → index d'expression B-tree.

Quand JSONB, quand colonne (la vraie décision)

JSONB est un outil, pas un défaut. La ligne de partage :

  • colonne SQL pour ce qui est : su Ă  l'avance, filtrĂ©/joint souvent, contraint (types, FK, NOT NULL), partagĂ© par tous les tenants. Le prix, le stock, le tenant_id — jamais en JSONB ;
  • JSONB pour ce qui est : variable par tenant, rarement filtrĂ© (souvent juste lu/affichĂ©), sans contrainte forte. Les attributs libres, les mĂ©tadonnĂ©es, un Ă©tat de jeu.

Le piĂšge classique : tout mettre en JSONB « pour la flexibilitĂ© » → on perd les contraintes, les FK, la lisibilitĂ© des requĂȘtes, et on rĂ©invente un schĂ©ma sans filet. Le projet Ă©tudiĂ© tranche par ADR : variant.name en JSONB (varie par tenant), price.level dĂ©normalisĂ© en colonne (filtrĂ© en permanence). Chaque champ, une dĂ©cision.

đŸ§© Quiz1/3

L'opérateur @> sur JSONB teste


🃏 Flashcards1/4