NoSQL ou SQL? Quando uso um, outro ou ambos
Henrique Lobo Weissmann (Kico)
Posted on June 21, 2021
Texto escrito em 2012
Na minha opinião o grande ganho que tivemos com o NoSQL foi o de nos acordar para o fato de que estávamos usando bancos de dados relacionais como a única opção para qualquer problema. Da até para parafrasear um famoso ditado:
"Dê para um desenvolvedor um banco de dados relacional e o mundo se torna um conjunto de tabelas"
O interessante é que foi criado tanto hype em cima destes bancos de dados que estes em diversas situações passaram de solução a problema por serem mal aplicados. Sobre a origem do hype já falei a respeito alguns posts atrás: é o desconhecimento do conceito de valor. Talvez seja até mesmo um sentimento pueril, a paixão por estar lidando com algo novo, o que fica bem claro quando topamos com o "logotipo padrão" do "movimento": a sigla SQL riscada, uma das metáforas mais tolas que já vi.
Neste post meu objetivo é expor quais os critérios que uso na adoção de um banco de dados, indiferente do fato deste ser relacional ou não.
Definição rápida: o que vêm a ser NoSQL?
Simples: qualquer banco de dados que não adote o paradigma relacional. Levando ao extremo o conceito, uma API que trabalhe com arquivos textuais poderia ser considerada um banco de dados NoSQL. O termo possuí duas conotações, uma inteligente e outra nem tanto, respectivamente not only SQL e no SQL.
A grosso modo vejo três grandes categorias: documentais, baseados em grafos e chave/valor. São as categorias com as quais tenho alguma experiência e que tratarei neste post.
Breve descrição de cada categoria de banco de dados
(Como o modelo relacional já é velho conhecido da esmagadora maioria dos programadores vou me dedicar aqui apenas às categorias NoSQL)
Documental
Talvez seja a categoria mais popular dos bancos de dados NoSQL. Se caracteriza pelo fato de não termos tabelas com um número fixo de campos bem definidos, mas sim coleções. Cada coleção pode armazenar um ou mais documentos (no lugar de registros em uma tabela). A grosso modo um documento é apenas um agregado de atributos que não possui uma regra rígida que definda quais os tipos de cada atributo e qual tipo cada um deve possuir (são sem esquema, schemaless). Normalmente os documentos são salvos num formato similar ao JSON, tal como pode ser visto no exemplo abaixo:
[code language="javascript"]
// Um documento usado para representar uma pessoa
{nome: "Henrique", sobrenome:"Lobo Weissmann", apelido:"Kico", cidade:"Belo Horizonte"}
// Um outro documenot para representar uma pessoa na mesma coleção
{nome: "Maria Angélica", sobrenome:"Álvares da Silva e Silva", profissao:"Advogada", caes:['Zé','Fraude']}
[/code]
Como pode ser visto no exemplo, eu posso ter registros bem diferentes um do outro dentro de uma mesma coleção. Soa estranho em um primeiro momento este tipo de abordagem, mas no modelo relacional a usamos de forma ineficiente o tempo inteiro sob a forma de tabelas esparsas. Uma tabela esparsa é aquela na qual vêmos uma multidão de colunas das quais apenas algumas são sempre preenchidas, e as demais apenas raramente. Para ilustrar esta situação, dê uma olhada na imagem a seguir, que representa um cadastro de equipamentos e materiais usados em uma obra.
Nesta tabela podemos ver um uso ruim do modelo relacional. Repare que há colunas cujo valor raríssimas vezes é preenchido, tal como pode ser visto no exemplo das colunas Altura de elevação e Diâmetro. Ao incluir colunas raramente usadas em nossa tabela, estamos na realidade jogando fora espaço de armazenamento e reduzindo a performance do sistema como um todo. Isto sem mencionar que tratamos objetos completamente diferentes como se fossem iguais, o que nem sempre é uma boa idéia. Podemos ver a seguir os mesmos dados sendo representados no modelo documental:
[code language="java"]
{codigo:1, tipo:"Britador", potencia:"300 cv", peso:"2000 kg", tag:"BR-121", motores:3}
{codigo:2, tipo:"Cimento"}
{codigo:3, tipo:"Rompedor de matacos", altura:"4 metros", peso:"300 kg", tag:"RM-11"}
{codigo:4, tipo:"Empilhadeira", potencia:"10 cv", peso:"400 kg"}
{codigo:5, tipo:"Transportador de correia", altura_elevacao:"2 m"}
{codigo:6, tipo:"Tubulação", diametro:"30 cm"}
[/code]
Se em seu sistema há tabelas esparsas, talvez seja um bom momento para que você avaliar um banco de dados documental. Aliás, eu já escrevi alguma coisa mais detalhada sobre este modelo neste blog, que você pode conferir neste link.
Bancos de dados que adotam este modelo: MongoDB, CouchDB.
Chave-valor
Trata-se da categoria mais simples e que talvez traga os maiores ganhos de performance quando bem aplicada. Neste modelo, toda consulta ao banco de dados é feita apenas através de uma chave, que pode ou não ter algum valor (de qualquer tipo) relacionado. É muito usado na implementação de caches de sistema ou acesso a informações que são alteradas em tempo real. De todos os modelos, é o que possuí tempo de pesquisa mais curto: basicamente é uma pesquisa baseada no hash da chave.
Em 2010 tive uma experiência muito bem sucedida com um banco de dados que usa esta abordagem, o Memcached, que você pode ver neste link. É um tipo de banco de dados muito usado também para substituir sistemas de mensageria como JMS, pois oferece um modelo mais simples de programação. No entanto, de todos os modelos é também o menos confiável sob o ponto de vista de persistência, pois são normalmente bancos desenvolvidos para armazenar informações em memória, com pouco foco na garantia de persistência (há excessões, mas leve isto como regra).
Bancos de dados que adotam este modelo: Berkeley DB, Memcached, Redis
Baseados em grafo
Talvez a menos popular das categorias, este modelo tem como foco o relacionamento entre os objetos. A metáfora neste caso é o grafo. Não temos mais coleções, apenas vértices representando os objetos de nosso sistema e arestas indicando o relacionamento entre estes. Normalmente cada vértice representa um agregado de atributos, muito similar ao modelo documental.
A pesquisa pode ser feita tanto por algum dos atributos dos vértices quanto pelos relacionamentos entre os mesmos. Neste tipo de banco de dados podemos fazer pesquisas do tipo "amigo do amigo". A aplicação mais óbvia é a sua lista de contatos em uma rede social. Outro exemplo interessante poderia ser a representação de alguma estrutura do tipo causa/efeito, como uma fábrica, em que cada etapa de produção gera a entrada para uma ou mais etapas que precisem ser monitoradas.
É interessante observar que aqui estamos lidando com um tipo de banco de dados que permite a aplicação de um modelo navegacional entre os elementos persistidos. O desenvolvedor pode, se quiser, caminhar no grafo ao implementar algoritmos de busca em profundidade ou busca do menor caminho.
Dica: escrever consultas por relacionamentos nestes bancos pdoe ser um processo muito chato. Uma ferramenta que tornará sua vida mais fácil se chama Gremlin, que a grosso modo é usado para escrever consultas mais complexas de forma simples. Depois dê uma olhada neste link.
Bancos de dados que adotam este modelo: Neo4J, VertexDB
Ganho em escalabilidade
Esse é um ponto controverso para mim. Vejo muita gente usando bases de dados NoSQL apenas para obter escalabilidade. Normalmente esta é obtida porque estes bancos de dados não implementam 100% do ACID e portanto passam a possuir funcionamento mais simples. Nem sempre isto é verdade: no caso do Neo4J, por exemplo, temos uma base de dados que o implementa 100%. Um outro argumento a favor destes bancos de dados é o de que consomem menos memória e configurar um cluster é mais simples. Tá: pode até ser, mas na minha opinião são argumentos que não tocam o núcleo da questão.
De nada adianta eu ter um banco de dados super leve se a estrutura de dados usada para armazenamento não for compatível com a modelagem do meu sistema. Se eu tenho um sistema simples como um blog, por exemplo, que ganho eu teria em implementá-lo usando um banco de dados do tipo chave/valor, documental ou baseado em grafos? Provávelmente nenhum, e o tal ganho em performance por parte do banco de dados seria perdido no parseamento feito pela minha aplicação.
Quando opto por uma base NoSQL difícilmente escalabilidade é A razão. O que realmente importa é que o modelo de persistência seja próximo da modelagem do meu sistema e que, com isto, minhas consultas sejam mais fáceis de serem escritas e o mapeamento entre o que está no banco de dados e minhas classes seja mais fácil e rápido de ser implementado e executado. Yeap: é neste ponto que o NoSQL passa a agregar valor.
Com relação a ganho de escalabilidade real, na minha experiência o único caso em que vejo isto ocorrer de forma mais fácil é com o modelo chave/valor implementando alguma forma de cacheamento. Em segundo lugar viria o uso de uma base documental quando lido com tabelas esparsas. Infelizmente ainda não tive a oportunidade de trabalhar em um sistema gigantesco em que pudesse ver isto funcionando (mas a itexto se interessa por este tipo de trabalho, sendo assim, caso queira implementar algo assim, nos procure ok? :D ).
Dificuldades com NoSQL
Nem tudo é lindo no mundo NoSQL. Há alguns problemas que ainda hoje podem me fazer evitar o uso de uma destas bases de dados. O primeiro destes problemas é o fato de que o vendor lock-in é certo. Como não há um padrão (e também não faz sentido existir um) a migração de um banco de dados para outro dentro de uma mesma categoria pode se mostrar uma tarefa bem trabalhosa.
Outro problema é a ausência de ferramentas de alto nível como as que encontramos no modelo relacional. Na maior parte das vezes me vejo usando apenas a linha de comando para fazer tudo o que preciso. No caso dos bancos de dados baseados em grafos a coisa está começando a melhorar com projetos como Gephi, por exemplo, mas ainda falta muito para que tenhamos um nível de qualidade satisfatório.
A curva de aprendizado também pode ser um problema. Como cada banco de dados apresenta a sua própria linguagem de consulta e manipulação, o desenvolvedor precisará adicionar cada vez mais e mais linguagens no seu cinto de utilidades.
Critérios de escolha: quando uso um ou outro (brinde incluso)
Desenvolvi uma planilha que atualmente possuí 15 critérios que me ajudam na escolha do modelo e você pode acessá-la a hora que quiser, bastando para isto clicar neste link (este é o brinde). O principal critério diz respeito à conformidade da minha modelagem com os modelos que conheço (incluindo o relacional). Caso o relacional se mostre o mais apto, sem sombra de dúvidas é o que irei adotar, deixando de lado os demais. Na maior parte das vezes, pelo menos o chave/valor é usado para otimizar uma ou outra parte dos meus sistemas.
É interessante observar que em 100% dos casos o modelo relacional sempre está presente. A razão para isto é muito simples: é o que atende ao maior número de casos e até hoje sempre me atendeu com excessão das situações que citei na breve descrição das categorias de bancos de dados que fiz acima. Ai que entra um detalhe muito importante pra mim:
Na prática os bancos de dados NoSQL complementam e não substituem o modelo relacional em minha experiência.
Caro Hypista, me desculpe jogar este banho de água fria em sua empolgação, mas a verdade para mim até este momento tem sido esta. Minhas tabelas relacionadas querendo ou não ainda atendem muito bem a esmagadora maioria das minhas necessidades enquanto arquiteto/desenvolvedor.
Concluindo
As bases de dados NoSQL são um excelente complemento para o modelo relacional, evitando que o apliquemos em situações para as quais não foi desenvolvido. A escolha por um modelo não relacional deve estar diretamente relacionada à compatibilidade da sua modelagem com uma ou outra categoria mais do que o mero ganho de performance.
Link para a planilha de critérios de seleção do modelo de banco de dados.
Posted on June 21, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.