Toate ghidurile

SQL vs NoSQL: cum alegi baza de date potrivită

Modele relaționale și NoSQL, ACID, CAP și scalare, plus întrebări practice care te ajută să alegi baza de date potrivită.


„Ce bază de date folosesc?” este una dintre primele decizii dintr-un proiect și una dintre cele mai greu de schimbat ulterior. Dezbaterea „SQL vs NoSQL” este adesea prezentată ca o luptă între tabere, dar în realitate este o alegere între modele de date și compromisuri diferite. Ghidul îți arată ce înseamnă fiecare, unde strălucește și cum alegi fără să te iei după modă.

Ce înseamnă de fapt „SQL” și „NoSQL”

  • SQL se referă la bazele de date relaționale: datele stau în tabele cu coloane definite, legate între ele prin chei, și sunt interogate cu limbajul SQL. Exemple: PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, SQLite.
  • NoSQL („not only SQL”) este o umbrelă pentru baze de date non-relaționale, foarte diferite între ele: de documente, cheie-valoare, wide-column, de grafuri. Singurul lucru comun este că nu folosesc modelul tabelar clasic.

Așadar întrebarea corectă nu este „SQL sau NoSQL?”, ci „ce model de date și ce garanții îmi trebuie?”.

Bazele de date relaționale

Într-o bază relațională definești schema dinainte, iar baza de date o impune. Exemplele de mai jos folosesc sintaxa PostgreSQL:

CREATE TABLE users (
  id         BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  email      TEXT NOT NULL UNIQUE,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE orders (
  id      BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  user_id BIGINT NOT NULL REFERENCES users(id),
  total   NUMERIC(10, 2) NOT NULL CHECK (total >= 0),
  status  TEXT NOT NULL DEFAULT 'pending'
);

Punctele forte:

  • Integritate. Constrângerile (NOT NULL, UNIQUE, CHECK, cheile străine) opresc datele invalide înainte să ajungă pe disc, indiferent ce bug are aplicația.
  • JOIN-uri și interogări ad-hoc. Poți pune întrebări la care nu te-ai gândit când ai proiectat schema:
SELECT u.email, COUNT(o.id) AS comenzi, SUM(o.total) AS valoare
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.status = 'paid'
GROUP BY u.email
ORDER BY valoare DESC
LIMIT 10;
  • Tranzacții ACID. Mai multe operații se execută ca un tot unitar:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

Dacă a doua operație eșuează, prima este anulată. ACID înseamnă Atomicity (totul sau nimic), Consistency (regulile și constrângerile rămân respectate), Isolation (tranzacțiile concurente nu se calcă pe picioare) și Durability (ce s-a confirmat supraviețuiește unei căderi).

Costul: schimbările de schemă cer migrări, iar distribuirea scrierilor pe mai multe servere este mai complicată decât la multe sisteme NoSQL.

Familiile NoSQL

TipCum stocheazăExemplePotrivit pentru
DocumentDocumente JSON/BSON grupate în colecțiiMongoDB, Couchbase, FirestoreDate cu structură variabilă, agregate citite împreună
Cheie-valoareO cheie → o valoareRedis, Valkey, DynamoDBCache, sesiuni, contoare, cozi simple
Wide-columnRânduri cu coloane flexibile, partiționate după cheieApache Cassandra, ScyllaDBVolume uriașe de scrieri: loguri, IoT, serii de timp
GrafNoduri și relații între eleNeo4jRețele sociale, recomandări, detecția fraudei

Câteva precizări:

  • Bazele de documente sunt cele la care se gândesc cei mai mulți când spun „NoSQL”. Un document poate conține obiecte și liste imbricate, iar două documente din aceeași colecție pot avea câmpuri diferite.
  • Redis este de obicei folosit alături de o bază principală, nu în locul ei. Ține datele în memorie, deci este extrem de rapid, dar setul de date trebuie să încapă în RAM.
  • Cassandra te obligă să proiectezi tabelele pornind de la interogări: fiecare mod de acces are, de regulă, propriul tabel, iar datele se duplică intenționat.

Aceleași date, două modele

Să luăm un blog cu articole și comentarii.

Modelul relațional folosește tabele separate, legate prin chei:

CREATE TABLE posts (
  id    BIGINT PRIMARY KEY,
  title TEXT NOT NULL,
  body  TEXT NOT NULL
);

CREATE TABLE comments (
  id      BIGINT PRIMARY KEY,
  post_id BIGINT NOT NULL REFERENCES posts(id),
  author  TEXT NOT NULL,
  text    TEXT NOT NULL
);

Modelul document pune articolul și comentariile într-un singur document:

{
  "_id": "post_42",
  "title": "Cum am trecut de la contabilitate la programare",
  "body": "Primul pas a fost...",
  "tags": ["reconversie", "backend"],
  "comments": [
    { "author": "Ana", "text": "Foarte util, mulțumesc!" },
    { "author": "Radu", "text": "Cât ți-a luat până la primul job?" }
  ]
}

Modelul document câștigă când citești aproape mereu articolul împreună cu comentariile: o singură citire, fără JOIN. Pierde când ai nevoie de toate comentariile unui utilizator, din toate articolele, sau când un articol popular adună zeci de mii de comentarii (în MongoDB, un document are o limită de 16 MB). Regula practică: încorporezi ce se citește împreună și rămâne mărginit ca dimensiune; referențiezi ce crește nelimitat sau este accesat independent.

Consistență, tranzacții și teorema CAP

Multe sisteme NoSQL distribuite au fost construite pentru disponibilitate și scalare, acceptând consistență eventuală: o scriere ajunge pe toate nodurile după un timp, iar între timp o citire poate returna o valoare veche.

Teorema CAP spune că, atunci când apare o partiție de rețea (nodurile nu mai pot comunica între ele), un sistem distribuit trebuie să aleagă între consistență (refuză să răspundă cu date posibil vechi) și disponibilitate (răspunde oricum). Două confuzii frecvente:

  • CAP nu înseamnă „alegi oricare două din trei” în condiții normale. Partițiile de rețea nu sunt opționale, iar alegerea contează doar atunci când apar.
  • În practică, multe sisteme sunt configurabile. Cassandra permite niveluri de consistență per interogare (ONE, QUORUM, ALL), iar MongoDB suportă tranzacții multi-document începând cu versiunea 4.0.

Pentru majoritatea aplicațiilor de business (comenzi, plăți, stocuri, conturi), garanțiile tranzacționale puternice sunt exact ce îți trebuie, iar cu o bază relațională le obții cel mai ușor.

Scalare: verticală și orizontală

AbordareCe înseamnăCând se potrivește
VerticalăUn server mai puternic (CPU, RAM, SSD)Prima opțiune pentru aproape orice bază de date
Read replicasCopii doar pentru citire ale bazei principaleAplicații cu multe citiri și relativ puține scrieri
ShardingDatele sunt împărțite pe mai multe servere după o cheieVolume de date sau de scrieri care nu mai încap pe un server

Bazele NoSQL precum Cassandra sau MongoDB au sharding-ul integrat din proiectare. La bazele relaționale este posibil, de exemplu cu extensia Citus pentru PostgreSQL sau cu Vitess pentru MySQL, dar cere mai multă muncă. Există și baze „distributed SQL”, precum CockroachDB, YugabyteDB sau Google Cloud Spanner, care oferă SQL și tranzacții peste mai multe noduri.

De reținut: un singur server PostgreSQL bine configurat, cu indecșii potriviți, duce o încărcare mult mai mare decât au nevoie majoritatea aplicațiilor. Scalarea orizontală este o problemă pe care s-o rezolvi când o ai, nu una pe care s-o anticipezi din prima zi.

Granița s-a estompat

În 2026, distincția este mult mai puțin tranșantă decât acum zece ani.

PostgreSQL are tipul JSONB, cu indecși GIN și operatori dedicați, deci poți ține date semi-structurate lângă cele relaționale (vezi documentația PostgreSQL despre tipurile JSON):

CREATE TABLE events (
  id      BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  payload JSONB NOT NULL
);

CREATE INDEX idx_events_payload ON events USING GIN (payload);

SELECT id FROM events WHERE payload @> '{"type": "signup"}';

MongoDB are validare de schemă (pe baza JSON Schema), tranzacții și agregări complexe, inclusiv operatorul $lookup, echivalentul unui JOIN. Detaliile sunt în manualul MongoDB.

Extensia pgvector adaugă în PostgreSQL căutarea după similaritate vectorială, folosită în aplicațiile cu AI pentru căutare semantică și RAG.

Consecința practică: o singură bază relațională acoperă adesea și cazurile pentru care, cândva, ai fi adăugat un sistem separat.

Cum alegi: întrebări practice

  1. Cum arată datele? Entități clare cu relații între ele (utilizatori, comenzi, produse, facturi) duc spre relațional. Agregate autonome cu structură variabilă (cataloage cu atribute diferite pe categorii, conținut generat de utilizatori) se potrivesc natural în documente.
  2. Cât de importantă este consistența? Bani, stocuri, rezervări: tranzacții ACID, fără compromis.
  3. Cum vei interoga datele? Rapoarte și întrebări ad-hoc cer SQL. Câteva modele de acces cunoscute dinainte, la volum foarte mare, pot justifica un sistem cheie-valoare sau wide-column.
  4. Ce volum ai, realist? Nu dimensiona arhitectura pentru milioane de utilizatori pe care încă nu-i ai.
  5. Ce știe echipa? O tehnologie pe care o cunoști bine bate o tehnologie „mai potrivită” pe care o înveți direct în producție.
ScenariuAlegere rezonabilă
Magazin online, SaaS, aplicație internăPostgreSQL sau MySQL
Cache, sesiuni, rate limiting, clasamenteRedis sau Valkey, lângă baza principală
CMS cu tipuri de conținut foarte variateMongoDB sau PostgreSQL cu JSONB
Telemetrie IoT cu volume foarte mari de scrieriCassandra, ScyllaDB sau o bază pentru serii de timp
Recomandări bazate pe relații „prietenul prietenului”Neo4j sau altă bază de grafuri
Aplicație mobilă sau desktop cu date localeSQLite

Varianta implicită sănătoasă pentru un proiect nou, mai ales la început de drum: PostgreSQL. Adaugi un sistem specializat atunci când ai o problemă concretă pe care baza principală nu o rezolvă bine.

Greșeli frecvente

  • „NoSQL nu are schemă, deci e mai flexibil.” Schema există oricum, doar că trăiește în codul aplicației, nu în baza de date. Fără validare, după un an ai documente cu cinci forme diferite pentru același tip de entitate.
  • Modelarea relațională într-o bază de documente. Colecții separate pentru orice, legate prin ID-uri și cu „JOIN-uri” făcute manual în aplicație, combină dezavantajele ambelor lumi.
  • Lipsa indecșilor. Fie că e SQL sau NoSQL, o interogare fără indexul potrivit scanează tot. Învață să citești planul de execuție: EXPLAIN ANALYZE în PostgreSQL, explain() în MongoDB.
  • Denormalizarea prematură. Într-o bază relațională, pornește de la o schemă normalizată și denormalizează punctual, doar acolo unde măsurătorile arată o problemă de performanță.
  • Alegerea după popularitate. Faptul că o companie uriașă folosește o anumită bază de date nu înseamnă că problemele tale seamănă cu ale ei.

Pașii următori

  • Învață SQL temeinic: este una dintre cele mai durabile competențe din IT. Începe cu roadmap-ul SQL și continuă cu roadmap-ul PostgreSQL.
  • Pentru imaginea de ansamblu (replicare, sharding, cache, consistență), parcurge System Design.
  • Exercițiu: modelează aceeași aplicație, de exemplu un mic magazin online, o dată în PostgreSQL și o dată în MongoDB, apoi scrie aceleași cinci interogări în ambele. Diferențele le vei simți imediat.