SQL x NoSQL: escolher o banco pelo formato do dado
Relacional, documento, chave-valor, colunar e grafo comparados pelo formato e pelo padrão de acesso do dado, não por moda. Um guia de decisão prático.
Neste artigo
Poucas decisões de arquitetura geram tanto debate improdutivo quanto a escolha entre SQL e NoSQL. A discussão costuma degenerar em torcida — "relacional é coisa do passado" contra "NoSQL não é banco de verdade" — quando deveria ser uma análise técnica fria. A verdade menos empolgante é que não existe banco melhor em abstrato. Existe o banco cujo modelo de dados se encaixa no formato da sua informação e no padrão de acesso da sua aplicação. Escolher pela moda, pelo que está no currículo do momento ou pelo que a última conferência elogiou é a receita para pagar caro depois.
A sigla NoSQL, aliás, é enganosa. Ela sugere uma coisa só, quando na verdade agrupa famílias de bancos radicalmente diferentes entre si — documento, chave-valor, colunar, grafo — que só têm em comum o fato de não seguirem o modelo relacional tradicional. Comparar "SQL versus NoSQL" é quase como comparar "carro versus não-carro". Para decidir bem, você precisa entender cada família pelo que ela realmente oferece e onde ela realmente dói.
Neste artigo vamos separar os modelos pelo formato do dado que cada um trata melhor, discutir as garantias que cada família dá e cobra, e chegar a um método de decisão que independe de tendência. O objetivo não é declarar um vencedor, mas dar a você critérios para escolher com consciência — e, muitas vezes, para descobrir que a resposta certa é usar mais de um banco para partes diferentes do problema.
O modelo relacional: dados estruturados e conectados#
O banco relacional organiza os dados em tabelas com esquema fixo, linhas e colunas tipadas, e conecta as tabelas por chaves. É o modelo por trás de PostgreSQL, MySQL, SQL Server e Oracle, e continua sendo o padrão sensato para a maioria dos sistemas transacionais.
Sua força aparece quando os dados são estruturados e altamente conectados. Um sistema de pedidos, clientes, produtos e pagamentos é um emaranhado de relacionamentos: um pedido pertence a um cliente, contém itens, cada item referencia um produto, cada pagamento liquida um pedido. O modelo relacional foi desenhado exatamente para isso. Ele oferece JOIN para recombinar essas tabelas de qualquer forma que a pergunta exija, transações ACID para garantir que operações que tocam várias tabelas aconteçam de forma atômica e consistente, e restrições declaradas — chaves estrangeiras, unicidade, CHECK — que impedem o banco de entrar em estados inválidos.
O esquema fixo, que às vezes é criticado como rigidez, é na verdade uma garantia. Ele obriga cada linha a respeitar uma forma conhecida, o que significa que a aplicação pode confiar que os dados têm a estrutura esperada. A linguagem SQL, madura e padronizada, permite fazer perguntas arbitrárias e complexas sem antecipar quais consultas você precisaria: agrupar, filtrar, cruzar e agregar de formas que você nem imaginava quando desenhou o schema.
O custo do relacional aparece na escala horizontal e em dados sem forma fixa. Distribuir um banco relacional por muitas máquinas mantendo as garantias ACID é difícil, porque JOIN e transações que cruzam nós são caros. E se seus dados são genuinamente heterogêneos — cada registro com um conjunto diferente de campos — forçá-los num esquema tabular pode ficar desconfortável. É aí que as outras famílias entram.
Bancos de documento: agregados que vivem juntos#
O banco de documento guarda cada registro como um documento auto-contido, tipicamente em formato JSON, com estrutura flexível e aninhada. MongoDB é o exemplo mais conhecido. Em vez de espalhar um pedido por várias tabelas, você guarda o pedido inteiro — com seus itens aninhados dentro dele — num único documento.
O encaixe ideal é quando o dado forma um agregado natural que é lido e escrito como um todo. Um perfil de usuário com suas preferências, um pedido com seus itens, um artigo com seus comentários: se você quase sempre acessa o conjunto inteiro de uma vez, guardá-lo junto elimina os JOIN e entrega tudo numa leitura só. O esquema flexível ajuda quando registros diferentes têm campos diferentes — um catálogo em que cada categoria de produto tem atributos próprios encaixa bem, porque cada documento carrega só os campos que fazem sentido para ele.
A contrapartida é que a flexibilidade transfere responsabilidade para a aplicação. Sem esquema imposto pelo banco, é a aplicação que precisa garantir que os documentos tenham a forma esperada, ou você acumula registros inconsistentes que só quebram na leitura. E dados muito conectados sofrem: se você precisa cruzar documentos de coleções diferentes com frequência, você está reinventando o JOIN na mão, geralmente com mais código e menos garantias do que o relacional daria de graça. Duplicar dados entre documentos para evitar essas junções cria o problema de manter as cópias em dia — a mesma anomalia de atualização que a normalização relacional existia para eliminar.
Chave-valor: o dicionário gigante e velocíssimo#
O banco chave-valor é o modelo mais simples: você guarda um valor associado a uma chave e o recupera pela chave, sem consultas complexas. Redis e DynamoDB (no seu uso mais básico) são exemplos. É essencialmente um dicionário distribuído e extremamente rápido.
O encaixe é quando o padrão de acesso é sempre por chave conhecida e a velocidade é crítica. Cache de sessão, cache de resultados caros, contadores, filas, dados que expiram — casos em que você sabe exatamente qual chave quer buscar e precisa da resposta em microssegundos. Como o modelo não oferece busca por conteúdo do valor nem junções, ele consegue ser absurdamente rápido e escalar horizontalmente com facilidade, distribuindo as chaves por muitas máquinas.
A limitação é o outro lado da simplicidade: você só acessa pela chave. Não dá para perguntar "quais valores têm tal atributo" sem varrer tudo, o que anula a vantagem. Por isso o chave-valor raramente é o banco principal de um sistema; ele costuma ser uma camada complementar, acelerando acessos por chave enquanto um banco mais rico guarda a fonte da verdade consultável.
Colunar: análise sobre volumes gigantescos#
O banco colunar armazena os dados por coluna em vez de por linha, o que o torna excepcional para agregações analíticas sobre grandes volumes. Exemplos incluem sistemas voltados a data warehouse e análise. A ideia é que, se você quer somar uma coluna sobre bilhões de linhas, ler só aquela coluna do disco é muito mais eficiente do que ler linhas inteiras das quais você usa um campo só.
O encaixe é o mundo analítico, o OLAP: relatórios, painéis, agregações sobre históricos enormes, consultas que varrem muitas linhas mas poucas colunas. Nesse cenário, o armazenamento colunar comprime melhor — valores da mesma coluna são parecidos e comprimem bem juntos — e lê só o que a consulta precisa, entregando desempenho que um banco orientado a linha não alcança.
A contrapartida é que ele é ruim para o mundo transacional, o OLTP: inserir, atualizar e ler registros individuais um a um. Escrever uma linha nova significa tocar em muitos arquivos de coluna, e buscar uma linha inteira é ineficiente. Por isso colunar e relacional costumam coexistir: o relacional atende as transações do dia a dia, e os dados são periodicamente copiados para um banco colunar onde as análises pesadas rodam sem competir com a operação.
Grafo: quando as conexões são o dado principal#
O banco de grafo modela os dados como nós e arestas, tratando os relacionamentos como cidadãos de primeira classe e otimizando a navegação por conexões. Neo4j é o exemplo mais citado. Em vez de descobrir relacionamentos com JOIN na hora da consulta, o grafo os armazena diretamente como ligações navegáveis.
O encaixe é quando as relações são o foco da pergunta, especialmente relações profundas e de comprimento variável: redes sociais ("amigos de amigos de amigos"), detecção de fraude ("esta conta se conecta a alguma conta marcada por até quantos passos"), motores de recomendação, grafos de conhecimento. Perguntas assim, num banco relacional, exigiriam JOIN recursivos que ficam exponencialmente caros conforme a profundidade cresce. No grafo, seguir uma aresta é uma operação barata e direta, então travessias profundas permanecem eficientes.
A contrapartida é a especialização: para dados que não são fundamentalmente sobre conexões, o grafo não oferece vantagem e adiciona complexidade operacional. Ele é a ferramenta certa para um tipo específico de problema, e desperdício para os demais.
Um método para decidir#
Fuja da pergunta "SQL ou NoSQL?" e faça perguntas melhores. Qual é o formato natural do meu dado — tabelas conectadas, agregados auto-contidos, pares chave-valor, colunas para agregar, ou uma teia de relações? Qual é o padrão de acesso dominante — busco por chave, cruzo entidades, agrego volumes, navego conexões? Quão fortes precisam ser minhas garantias transacionais — preciso de ACID sobre várias entidades, ou consistência eventual basta? Como preciso escalar — vertical é suficiente, ou preciso distribuir por muitas máquinas?
As respostas apontam a família naturalmente. Dados conectados com transações fortes e consultas imprevisíveis: relacional, e comece por ele por padrão, porque a maturidade e a flexibilidade de consulta cobrem a maioria dos casos. Agregados lidos como um todo com esquema variável: documento. Acesso por chave com velocidade extrema: chave-valor como camada complementar. Análise sobre volumes históricos: colunar. Relações profundas como o próprio problema: grafo.
A arquitetura poliglota#
A conclusão mais madura costuma ser que a escolha não é exclusiva. Sistemas reais frequentemente usam persistência poliglota: um banco relacional como fonte da verdade transacional, um chave-valor para cache e sessão, um colunar para análise, talvez um grafo para um subproblema de recomendação. Cada parte do sistema usa o banco cujo modelo encaixa naquela necessidade. Isso adiciona complexidade operacional e precisa ser justificado, mas é honesto quanto ao fato de que um único modelo raramente é ótimo para tudo.
Fechando o raciocínio#
A escolha entre SQL e NoSQL não é uma questão de moda nem de qual tecnologia é mais moderna. É uma questão de encaixe entre o modelo de dados do banco e a natureza da sua informação e do seu acesso. O relacional continua sendo o ponto de partida sensato para a maioria dos sistemas transacionais, pela sua combinação de garantias fortes e flexibilidade de consulta. As famílias NoSQL não o substituem em geral; elas resolvem melhor problemas específicos onde o relacional é desconfortável — agregados auto-contidos, acesso por chave em altíssima velocidade, análise sobre volumes colossais, travessia de relações profundas.
Decidir bem é conhecer o formato do seu dado e o padrão do seu acesso, e escolher a ferramenta que se encaixa neles — inclusive quando isso significa usar mais de uma. A pior escolha é a feita por torcida, porque ela cobra o preço em cada consulta desconfortável e em cada garantia que você descobre, tarde demais, que o banco escolhido não oferecia.