← Back to Cooldecode
Lesson 12 · Data & backend

Relational vs non-relational databases: the real comparison

Now that SELECT / WHERE / JOIN click, the next question is why entire categories of databases exist that skip tables altogether — and when that trade actually pays off.

1. What "relational" actually means

A relational database (SQL database — Postgres, MySQL, SQLite) stores data in tables with a fixed schema: every row in a table has the same columns, and tables relate to each other through foreign keys (a user_id column in an orders table pointing back to the users table). The word "relational" refers to those relationships between tables, not to relationships between people or objects in your app.

The engine enforces the schema at write time. If a column is defined as an integer, the database rejects a write that tries to put text in it. If you delete a user, a foreign key constraint can stop you from leaving orphaned orders behind. That enforcement is the whole value proposition: consistency is guaranteed by the database itself, not by application code remembering to check.

2. What "non-relational" covers — it's not one thing

Non-relational (commonly called NoSQL, though the name is a historical accident more than an accurate description) is an umbrella term for databases that don't organize data as rows in fixed-schema tables. That's the only thing they all have in common — under that umbrella sit at least four genuinely different data models, each solving a different problem.

The naming trap: "NoSQL" makes it sound like one alternative to SQL. It isn't. Document stores, key-value stores, wide-column stores, and graph databases have almost nothing in common with each other beyond "not relational tables." Comparing "SQL vs NoSQL" as if it were a single choice is the most common mistake in this conversation.

3. The core trade-off: structure vs flexibility

RelationalNon-relational
Fixed schema, enforced by the databaseFlexible or no schema — enforcement (if any) happens in application code
Strong consistency by default (ACID transactions)Often trades strict consistency for availability and speed at scale
Joins across tables are a first-class operationData is usually denormalized — related data is duplicated inside one record to avoid joins
Scales vertically first, horizontally with more effort (sharding)Many were built horizontal-scaling-first, distributing across many machines by design
Best fit: data with clear, stable relationshipsBest fit: data that's naturally nested, high-volume, or schema-varies-per-record

Neither column is "better" in the abstract. The trade-off is real: rigid structure buys you correctness guarantees and powerful querying across relationships; flexible structure buys you a shape that matches your data more naturally and can scale out more easily, at the cost of pushing consistency checks into your application.

4. The main types of non-relational databases

TypeStores data asExamplesTypical use
DocumentJSON-like documents, each can have a different shapeMongoDB, Firestore, CouchbaseContent with nested, variable structure — user profiles, product catalogs, CMS content
Key-valueA key mapped to an opaque value, no query language into the value itselfRedis, DynamoDB, MemcachedCaching, session storage, feature flags — anything needing extremely fast lookups by a known key
Wide-columnRows with a huge, sparse, flexible set of columns, optimized for massive scaleCassandra, HBase, BigtableTime-series data, IoT telemetry, write-heavy workloads at enormous scale
GraphNodes and edges, where the relationships themselves are first-class dataNeo4j, Amazon NeptuneSocial networks, recommendation engines, fraud detection — anything where "how things connect" is the actual question

Notice the irony: graph databases are, in a sense, more relationship-focused than relational databases — they just model relationships as direct pointers between records instead of foreign keys resolved through joins.

5. When relational wins

6. When non-relational wins

7. Can you use both? Polyglot persistence

Yes, and most non-trivial systems already do, whether or not the team calls it that. A common pattern: Postgres (relational) as the source of truth for users, orders, and billing, Redis (key-value) as a cache in front of it, and maybe Elasticsearch (a specialized search-oriented store) for full-text search over product descriptions. This is called polyglot persistence — using the right storage engine per problem instead of forcing every use case through one database.

The catch: every additional data store is another system to operate, another place data can get out of sync, and another thing a new engineer has to learn. Polyglot persistence is a real technique, not a default — reach for a second database engine when a specific access pattern genuinely doesn't fit the first one, not because the option exists.

8. A practical example

Take an e-commerce app. Orders, payments, and inventory counts — data with strict consistency needs and clear relationships — sit naturally in Postgres. Product search-as-you-type benefits from a search-optimized store. The shopping cart, which needs to be read and written on almost every page load but tolerates being lost if a user never checks out, is a textbook Redis use case. None of these choices contradicts the others; each one matches a specific access pattern to the storage engine built for it.

The question to ask for any new piece of data isn't "SQL or NoSQL" in the abstract — it's "does this data have a fixed shape, does it need transactional guarantees, and how is it actually going to be queried." The answer to those three questions almost always points you to the right category on its own.

Newsletter

Learn what AI is creating for you. Don't get lost.

Get notified when a new deep dive or lesson goes up. No spam, just new posts.

Lição 12 · Dados e backend

Bancos relacionais vs não-relacionais: a comparação de verdade

Agora que SELECT / WHERE / JOIN fizeram sentido, a próxima pergunta é por que existem categorias inteiras de banco de dados que abandonam tabelas de vez — e quando essa troca realmente vale a pena.

1. O que "relacional" realmente significa

Um banco de dados relacional (banco SQL — Postgres, MySQL, SQLite) guarda dados em tabelas com esquema fixo: toda linha de uma tabela tem as mesmas colunas, e as tabelas se relacionam entre si por chaves estrangeiras (uma coluna user_id numa tabela orders apontando de volta pra tabela users). A palavra "relacional" se refere a essas relações entre tabelas, não a relações entre pessoas ou objetos da sua aplicação.

O motor do banco aplica o esquema no momento da escrita. Se uma coluna é definida como número inteiro, o banco rejeita uma escrita que tente colocar texto ali. Se você deleta um usuário, uma restrição de chave estrangeira pode te impedir de deixar pedidos órfãos. Essa aplicação de regra é toda a proposta de valor: consistência garantida pelo próprio banco, não por código de aplicação que precisa lembrar de checar.

2. O que "não-relacional" cobre — não é uma coisa só

Não-relacional (comumente chamado de NoSQL, embora o nome seja mais um acidente histórico que uma descrição precisa) é um termo guarda-chuva pra bancos que não organizam dados como linhas em tabelas de esquema fixo. Isso é a única coisa que todos têm em comum — debaixo desse guarda-chuva ficam pelo menos quatro modelos de dados genuinamente diferentes, cada um resolvendo um problema distinto.

A armadilha do nome: "NoSQL" faz parecer que é uma alternativa única ao SQL. Não é. Bancos de documento, chave-valor, coluna larga e grafo têm quase nada em comum entre si além de "não são tabelas relacionais". Comparar "SQL vs NoSQL" como se fosse uma escolha só é o erro mais comum dessa conversa.

3. O trade-off central: estrutura vs flexibilidade

RelacionalNão-relacional
Esquema fixo, aplicado pelo bancoEsquema flexível ou inexistente — a aplicação (se houver) fica com essa checagem
Consistência forte por padrão (transações ACID)Frequentemente troca consistência estrita por disponibilidade e velocidade em escala
Joins entre tabelas são uma operação de primeira classeDados geralmente desnormalizados — dados relacionados são duplicados dentro de um registro pra evitar joins
Escala verticalmente primeiro, horizontalmente com mais esforço (sharding)Muitos foram construídos pra escalar horizontalmente desde o início, distribuindo por várias máquinas por design
Melhor encaixe: dados com relações claras e estáveisMelhor encaixe: dados naturalmente aninhados, de alto volume, ou com esquema variando por registro

Nenhuma coluna é "melhor" no abstrato. O trade-off é real: estrutura rígida compra garantias de correção e consultas poderosas entre relações; estrutura flexível compra um formato que combina mais naturalmente com seus dados e escala mais fácil pra fora, ao custo de empurrar checagens de consistência pra sua aplicação.

4. Os principais tipos de banco não-relacional

TipoGuarda dados comoExemplosUso típico
DocumentoDocumentos parecidos com JSON, cada um pode ter um formato diferenteMongoDB, Firestore, CouchbaseConteúdo com estrutura aninhada e variável — perfis de usuário, catálogo de produtos, conteúdo de CMS
Chave-valorUma chave mapeada a um valor opaco, sem linguagem de consulta dentro do valorRedis, DynamoDB, MemcachedCache, armazenamento de sessão, feature flags — qualquer coisa que precise de busca extremamente rápida por uma chave conhecida
Coluna largaLinhas com um conjunto enorme, esparso e flexível de colunas, otimizado pra escala massivaCassandra, HBase, BigtableDados de série temporal, telemetria de IoT, cargas de trabalho pesadas em escrita e em escala enorme
GrafoNós e arestas, onde as próprias relações são dados de primeira classeNeo4j, Amazon NeptuneRedes sociais, motores de recomendação, detecção de fraude — qualquer coisa onde "como as coisas se conectam" é a pergunta real

Note a ironia: bancos de grafo são, em certo sentido, mais focados em relações que bancos relacionais — só modelam relações como ponteiros diretos entre registros em vez de chaves estrangeiras resolvidas por joins.

5. Quando o relacional vence

6. Quando o não-relacional vence

7. Pode usar os dois? Persistência poliglota

Sim, e a maioria dos sistemas não-triviais já faz isso, mesmo que o time não chame por esse nome. Um padrão comum: Postgres (relacional) como fonte da verdade pra usuários, pedidos e cobrança, Redis (chave-valor) como cache na frente dele, e talvez Elasticsearch (um banco especializado em busca) pra busca textual sobre descrições de produto. Isso se chama persistência poliglota — usar o motor de armazenamento certo pra cada problema em vez de forçar todo caso de uso por um banco só.

A pegadinha: cada banco adicional é mais um sistema pra operar, mais um lugar onde dados podem ficar fora de sincronia, e mais uma coisa que um engenheiro novo precisa aprender. Persistência poliglota é uma técnica real, não um padrão a seguir por padrão — recorra a um segundo motor de banco quando um padrão de acesso específico genuinamente não se encaixa no primeiro, não porque a opção existe.

8. Um exemplo prático

Pega um app de e-commerce. Pedidos, pagamentos e contagem de estoque — dados com necessidade estrita de consistência e relações claras — ficam naturalmente no Postgres. Busca de produto enquanto você digita se beneficia de um banco otimizado pra busca. O carrinho de compras, que precisa ser lido e escrito em quase todo carregamento de página mas tolera ser perdido se o usuário nunca finaliza a compra, é um caso de uso de manual pro Redis. Nenhuma dessas escolhas contradiz as outras; cada uma casa um padrão de acesso específico com o motor de armazenamento construído pra ele.

A pergunta a fazer pra qualquer dado novo não é "SQL ou NoSQL" no abstrato — é "esse dado tem formato fixo, precisa de garantias transacionais, e como ele vai ser consultado de fato". A resposta a essas três perguntas quase sempre aponta pra categoria certa por conta própria.

Newsletter

Saiba o que a IA está criando pra você. Não fique por fora.

Seja avisado quando eu postar uma imersão ou lição nova. Sem spam, só posts novos.