Parte 1 – Dando Superpoderes aos Seus Dados com Neo4J e Grafos

novembro de 2021

Autor: Lucas Humberto Cabrera Santos

Estamos extremamente acostumados a utilizar bancos de dados relacionais e não relacionais, mas você já parou para se perguntar por que esses tipos de bancos são tão utilizados? Você já parou para pensar que talvez o modelo que você esteja utilizando para armazenar seus dados pode não ser o ideal? 

Nossa quantidade de dados cresce exponencialmente a cada dia, isso é um problema que temos que lidar diariamente, porém será que esse é o único problema? 

Bancos Relacionais 

Os bancos relacionais foram criados em meados de 1970, desde então eles têm sido o principal modelo de armazenamento de dados que tivemos, porém eles não são os mais simples e nem os mais rápidos bancos de dados que existem, por que então ainda utilizamos eles?  

Simplesmente pelo fato de que, por ser um padrão muito antigo a comunidade adotou boas práticas e construiu todo um ecossistema sobre esse paradigma, então como uma biblioteca muito famosa, a comunidade cresceu ao redor desse tipo de banco de dados e se estabeleceu como o padrão primário para essa função. 

O Problema dos Relacionamentos 

Bancos de dados relacionais tem esse nome justamente porque gerenciam os relacionamentos entre dois ou mais dados. Por exemplo, vamos imaginar uma ACL (Access Control List) com uma matriz de permissões, um usuário pode estar atrelado a um ou mais Roles em uma aplicação, ele pode ser um operador e ao mesmo tempo, um visualizador de dados. Cada Role possui uma série de escopos permissivos como: Inserir novo cliente, alterar cliente, remover cliente, extrair relatório e etc. É um Modelo Relacional aproximadamente como o representado abaixo: 

Veja que temos duas tabelas de relacionamento para podermos relacionar um usuário com mais de um Role ao mesmo tempo e também para relacionar um Role a mais EM um escopo. Se quisermos saber quais são as permissões de um usuário, teremos que fazer uma Query com os seguintes passos: 

  1. Encontrar o role do usuário buscando SELECT roleId FROM TBL_USUARIO_ROLE WHERE userId = <id> 
  1. Encontrar qual é o ID do escopo do role que estamos buscando com SELECT scopeId FROM TBL_ROLE_SCOPE WHERE roleId = <id> 
  1. A query anterior vai nos retornar uma lista de escopos, então temos que pegar todos os escopos que estão pertinentes a ele com uma query SELECT scopeName FROM TBL_SCOPE WHERE scopeId IN (<lista>) 

Obviamente podemos transformar isso tudo em uma única Query utilizando JOINS e coletando todos os dados em um único comando, porém o mais alarmante aqui é o número de relacionamento que fizemos. Perceba que, para cada usuário temos pelo menos dois novos relacionamentos, o usuário com o Role e o Role com o usuário. 

Esse é o grande problema que enfrentamos atualmente, pois como expliquei anteriormente, os nossos dados estão crescendo exponencialmente de forma diária, esse é um problema que os bancos de dados atuais já resolvem de forma satisfatória, o número de dados e a busca por eles já foi resolvida de várias maneiras diferentes ao longo dos anos, mas, além dos dados, há outro fator que cresce duas vezes mais rápido: Os relacionamentos

Como no nosso exemplo anterior, para cada novo dado na tabela de usuário, criamos dois novos relacionamentos, isto é uma taxa de crescimento de dois para um, ou seja, sempre teremos o dobro de relacionamentos do que os nossos dados. 

Bancos não relacionais 

Para resolver o problema do crescimento dos relacionamentos, tivemos uma ideia interessante: Removemos os relacionamentos dos bancos. E foi assim que os modelos não relacionais foram criados, isso aumentou muito a velocidade com o que coletamos dados e informações do banco, mas veio ao custo de não termos as verificações de integridade e Constraints que os bancos relacionais nos davam por padrão, mas como todas as coisas, sempre que resolvemos um problema, criamos outro problema igualmente complexo.  

Vamos ao nosso mesmo exemplo de ACL anterior. Imagine que agora estamos usando MongoDB para armazenar todos os nossos dados. Temos uma coleção de usuários, mas então caímos no dilema dos Embedded Documents: Devemos incluir os Roles dentro do usuário? Ou devemos referenciar os usuários nos Roles

Fora esse questionamento temos mais vários que podemos seguir: 

  • Devemos incluir os Roles dentro do usuário ou não? 
  • Prós: Teremos sempre uma Query única que trará o usuário e seus Roles 
  • Contra: Se o role mudar por algum motivo, temos que atualizar todos os usuários 
  • Seguindo a ideia acima, devemos incluir os Scopes dentro dos roles ou referenciá-los apenas? 
  • Prós: Somente uma Query para coletar tudo sobre o usuário (desde que os Roles estejam dentro do mesmo) 
  • Contras: Scopes podem ser adicionados ou removidos, vamos ter que alterar todo mundo se um role ganhar ou perder um escopo 
  • Se separarmos usuários e Roles, mas mantivermos os Scopes dentro dos Roles? 
  • Prós: Não precisamos atualizar os usuários se os roles mudarem 
  • Contras: Temos que lidar com integridade referencial no nosso código 
  • Se separarmos tudo, usuários, Roles e escopos, em Collections diferentes 
  • Prós: Temos controle fino de cada entidade sem precisar atualizar o banco todo 
  • Contras: Muitas Queries para trazer informação, a integridade referencial fica mais complexa 

Veja que agora temos que nos preocupar com a localização e a modelagem dos documentos, que pode ser boa em determinados casos ou ruim para outros casos, além disso, utilizar relacionamentos em um banco não relacional soa um pouco estranho, já que poderíamos facilitar muito a nossa vida simplesmente usando um banco relacional. 


Compartilhe nas redes sociais Compartilhe nas redes.