Nos sistemas e nas aplicações que são criadas hoje em dia, os maiores problemas com Dados em geral são a quantidade de informações geradas, os múltiplos formatos que existem, e a velocidade em que eles se modificam.
Nesse post eu vou comentar um pouco sobre esse tema, e duas maneiras de lidar com isso.
Quando a gente desenvolve
um sistema hoje em dia, normalmente nós usamos várias tecnologias que tem a ver
com Dados, mas cada uma tem uma finalidade específica, por exemplo:
Quando você armazena dados com objetivo de alguém ler depois, você usa um banco de dados;
Se você quer lembrar o resultado de uma busca complexa, para acelerar leituras, você usa um mecanismo de cache;
Para permitir que os usuários façam buscas por palavras-chave específicas, textos-livres, ou consultas ad-hoc, você usa índices;
Para trocar mensagens entre processos, ou entre sistemas, você usa um broker de eventos;
E para periodicamente pegar uma grande quantidade de dados acumulados e processar, você faz um processamento batch.
Nós tipicamente pensamos que bancos de dados, caches, filas, são todas ferramentas de diferentes categorias. Por exemplo, um banco de dados e um broker de eventos têm uma certa similaridade, porque ambos armazenam dados por algum tempo. Mas eles são diferentes. Eles têm padrões de acesso diferentes, e características de performance e implementação diferentes.
Além disso, pra cada uma dessas categorias existem dezenas de opções com base em diferentes capacidades. Existem vários tipos de bancos de dados, várias formas e métodos diferentes de fazer cache, e vários tipos de índices para buscar informações. E isso ocorre basicamente porque os sistemas TÊM necessariamente requerimentos diferentes.
E quando a gente desenvolve um sistema, especialmente na camada de persistência, na camada de dados, a gente precisa saber quais ferramentas e quais métodos são os mais apropriados para cada caso, e é difícil combinar ferramentas diferentes quando você precisa fazer uma coisa que uma só ferramenta sozinha não consegue fazer, certo?
A verdade é que no final do dia você, além de você ser um desenvolvedor de software, acaba sendo também um arquiteto de dados.
Então basicamente você tem dois caminhos.
Você tem o caminho onde você vai utilizar várias tecnologias. Você vai aprender todas essas ferramentas. Você vai integrar todas elas. Vai suportar todas elas, e vai garantir que elas funcionem em conjunto.
E você tem um outro caminho. O caminho que eu chamo de “um sistema de dados convergente”. E nesse sistema você tem uma plataforma, e nessa plataforma você tem quase todas as ferramentas, quase todos os tipos de dados… seja schema on write, seja schema on read, seja um cache, uma fila, não importa o formato dos dados… todos eles, dentro do mesmo sistema de dados. E quando esse sistema não suporta alguma coisa, ele virtualiza o acesso e expõe a mesma interface de acesso pra você consumir aquela informação da forma mais transparente possível.
Atualmente existem mais de 300 bancos de dados no mercado, e você precisa escolher aquele que melhor atende sua necessidade.
Os projetistas desses bancos de dados fizeram uma importante decisão sobre como eles devem funcionar, e por isso é importante entender o mecanismo de funcionamento deles para você não errar na escolha.
Entendendo o Teorema CAP você terá uma visão mais clara sobre os tipos de bancos de dados disponíveis, e quais estão aderentes ao seu caso de uso.
Nesse post eu passo uma visão básica sobre o significado do Teorema CAP. Você também pode assistir meu video no YouTube:
Consistency, Availability and Partition Tolerance (CAP)
CAP significa Consistência [do inglês, Consistency], Disponibilidade [do inglês, Availability], e Tolerância a Partição [do inglês, Partition Tolerance].
Partition Tolerance significa que o banco de dados é distribuído em diversos servidores independentes [shared-nothing], em pares de leitura/escrita. Isso é importante, em especial, para aumentar a performance, já que quanto mais você espalha os dados em servidores diferentes, maior é o throughput [megabytes por segundo] de leitura e escrita. Partition Tolerance também significa que se um servidor estiver fora, todo o sistema de banco de dados continua funcionando, com exceção desta parte específica que apresentou a falha.
Você pode perguntar por que P é chamado exatamente de “Tolerância a Partição”. O entendimento de partição aqui é “falha”, e mais especificamente falha de rede, que impede que um servidor se comunique com outro servidor. Então quando um banco de dados tolera partição, significa que se houver falha na comunicação entre um servidor que escreve e sua réplica, o banco de dados não para de funcionar, pois poderá haver outros pares de leitura e escrita no cluster que não estão no caminho da rede que falhou.
Consistency implica em consistência de leitura, e significa que depois que uma informação é escrita, todas as leituras subsequentes vão enxergá-la, no mesmo servidor, ou em suas réplicas. Neste caso também dizemos que há consistência forte, porque todos enxergam a mesma versão da informação.
Availability significa sempre disponível para leitura ou escrita, e todas as requisições sempre retornam alguma informação, mesmo que ela esteja inconsistente – mas nunca retorna um erro. Isto é, pode ter havido alguma falha na rede e os pares de servidores leitura/escrita não se enxergam, mas ambos permanecem abertos e recebem operações, estando em estado eventualmente consistente. Por causa disso, também dizemos que há uma consistência eventual, porque não é certeza que todos enxergam a mesma versão da informação.
A Prova
O Teorema CAP foi provado, e ele diz que das três propriedades desejadas, apenas duas podem existir ao mesmo tempo para um par leitura/escrita.
Isso nos leva a três possibilidades que definem o mecanismo de funcionamento de um banco de dados.
CA – Consistency e Availability: são bancos de dados cujos dados não estão distribuídos, mas oferecem consistência, e também disponibilidade [porém, em geral através de failover, isto é, com downtime]. O Oracle RAC é o único atualmente que oferece tanto C como A “sem downtime” em um sistema de banco de dados que não tolera partição [shared-disk].
CP – Consistency e Partition Tolerance: são bancos de dados que oferecem consistência, isto é, os pares leitura/escrita sempre estão com os mesmo dados [consistentes], mas caso haja alguma falha na rede, ambos tornam-se indisponíveis: sacrificam a disponibilidade em favor da consistência.
AP – Availability e Partition Tolerance: são bancos de dados que oferecem disponibilidade, e sacrificam a consistência. Isto é, os pares leitura/escrita permanecem operantes quando há falha na rede. Notadamente, quando isto ocorre eles ficam em estado inconsistente, pois não há uma comunicação entre eles. A inconsistência pode ser resolvida quando a comunicação é reestabelecida.
Minha Opinião… e a Sua?
Primeiramente, a letra A do CAP implica em uma premissa que eu particularmente não concordo.
A significa sempre disponível para leitura e escrita, mas sabemos que disponibilidade é medida em 9s depois da vírgula, e nada é realmente 100%. Quanto mais rotas redundantes de rede, e mais réplicas dos dados, mais 9s de disponibilidade teremos depois da vírgula, mas nunca 100% como o teorema preconiza.
Um outro ponto é que potencialmente, salvo implementação específica de cada banco de dados, os sistemas AP sempre apresentam um estado de consistência eventual, mesmo sem falha/partição na rede. Isso ocorre porque a propagação dos dados entre o servidor de que escreve e o servidor de réplica é assíncrona. Desta forma uma leitura pode ocorrer antes que uma informação que acabara de ser escrita fosse transmitida pela rede até o servidor em questão. Considerando que atualmente falhas de rede são raras, e as redes de comunicação locais são rápidas, sistemas AP oferecem uma desvantagem permanente, e na minha visão, desnecessária, tornando-os nicho para necessidades muito específicas. Há uma tendência de mercado dos bancos de dados NoSQL migrarem para o paradigma CP.
Então antes de usar um banco de dados, em especial nesses tempos de micro-serviços e persistência poliglota, atente-se ao mecanismo que é implementado no banco de dados.
Requisitos de elasticidade e alto throughput para leitura e escrita exigem que o banco de dados seja tolerante a partições. E neste caso, se houver a necessidade de consistência forte, o banco de dados deverá ser CP, do contrário, escolha AP.
Sistemas de banco de dados são como vinhos, queijos e árvores. Eles melhoram enquanto envelhecem.
Em um projeto complexo, com requisitos de alta performance, escalabilidade e disponibilidade para a camada de persistência, de todas as decisões que você deve tomar, nenhuma é mais desafiadora – e nenhuma outra tem recebido mais atenção – do que ESCOLHER O BANCO DE DADOS MAIS ADEQUADO [a engenharia do Uber que o diga]. O que torna tal decisão tão difícil não é só a quantidade de opções que existe [são mais de 300 bancos de dados para os mais diversos fins].
Os sistemas Relacionais são os mais populares, suportam nativamente SQL [que é a melhor linguagem para consultar e manipular dados], e são os melhores em integridade – mas sabidamente eles não escalam de forma eficiente, e têm baixa flexibilidade. Os sistemas NoSQL escalam horizontalmente, são extremamente flexíveis e suportam dados variados, mas pecam na consistência [que é eventual]. Os sistemas NewSQL são um avanço dos NoSQL, têm maior consistência, maior suporte ao SQL, porém com menor disponibilidade em relação ao anterior. Os sistemas Multi-Model são uma combinação do Relacional com o NoSQL, porém não absorvem todas as características de arquitetura de cada um. Multi-Model é uma capacidade que todos os anteriores podem ter.
A GRANDE DIFICULDADE está em escolher aquele que atenda aos requisitos atuais, MAS QUE TAMBÉM ATENDA AOS REQUISITOS FUTUROS que você ainda não sabe quais são. Isso pode te deixar na mão se o sistema de banco de dados escolhido não tiver a capacidade de se adequar ao dinamismo que estamos vivenciando, como desenvolvimento ágil, microserviços, aplicações cloud native, machine learning, blockchain e IoT.
Pare por um momento e responda: Você Tem Dúvidas para Decidir Qual é a Camada de Persistência Mais Adequada para seu Próximo Projeto? Espero que este panorama lhe ajude a ter uma visão mais clara.
Relacional é SQL, e SQL é Relacional: uma Simbiose dos Anos 70 que é Atual até Hoje
SQL e o sistema de banco de dados Relacional transformaram em museu rapidamente tudo que existia antes. Inovações como acesso client/server, joins, locks no nível de linha, leitura consistente, transações locais e distribuídas, e constraints, só para citar alguns, foram capazes de aliviar os desenvolvedores da época, e substituir milhares de linhas de código por uma simples frase: SELECT FROM WHERE. A evolução do SQL foi um dos acontecimentos mais importantes na década de 80 na área de tecnologia, pois mudou a forma como a informação era utilizada, e como os sistemas eram construídos.
A linguagem SQL e o sistema Relacional surgiram, e milhares de linhas de código foram substituídas por uma simples frase: SELECT FROM WHERE.
A linguagem SQL, utilizada para buscar e manipular dados em um banco Relacional, é amplamente “simulada” sob outros formatos NoSQL, porque, no final do dia, SQL é uma das linguagens mais simples do universo!
Hoje em dia SQL é extremamente robusto: ele permite não só consultar e manipular dados, mas também permite fazer data wrangling de forma muito eficiente, fornece capacidade nativa para reconhecimento de padrões, expressões regulares, aprendizado de máquina, funções analíticas, e possui uma biblioteca de APIs bastante abrangente em todas as implementações de banco de dados.
A Força Bruta de Consistência
Outra característica marcante nos sistemas Relacionais é a INTEGRIDADE. Quando o objetivo é integridade, nada construído até hoje é mais rápido e mais simples do que o sistema de banco de dados Relacional. Há quase 40 anos ele tem sido o padrão para armazenamento na maioria dos sistemas de informação, porque a maioria dos sistemas precisa de integridade.
As propridades ACID [Atomicidade, Consistência, Isolamento e Durabilidade] são os fundamentos da integridade nos sistemas Relacionais, e ao lado da linguagem SQL, são vistas como as principais características deste modelo de persistência.
ATOMICIDADE: se uma transação tem vários comandos, ou faz tudo, ou não faz nada; CONSISTÊNCIA: a transação respeita a unicidade da chave primária, o valor que não pode ser nulo, a chave estrangeira, os datatypes e quaisquer outras regras definidas na tabela; ISOLAMENTO: uma transação não enxerga a outra que atua no mesmo dado. Um produto tem 1 unidade e duas compras são realizadas ao mesmo tempo: uma deve executar primeiro. Se a primeira efetivar, a segunda não consegue comprar o produto [por falta de estoque]. Se a primeira falhar, a segunda efetiva a compra do produto; DURABILIDADE: o dado alterado por uma transação persiste em disco, e este sempre será o mesmo até que outra transação válida o altere.
Para garantir a integridade em transações distribuídas, os sistemas Relacionais utilizam o protocolo Two-Phase Commit, conhecido como 2PC, para garantir a atomicidade [A do ACID].
Quando uma transação é distribuída entre vários bancos de dados, quando um deles faz commit, todos votam, e caso todos votem ‘sim’, eles registram o commit em logs locais – ou rollback, caso pelo menos um vote ‘não’, ou haja qualquer falha [fase 1]. Supondo que todos votem ‘sim’, a confirmação é retornada para todos, e a transação é efetivada em todos os bancos de dados [fase 2]. O log de confirmação local garante que todos podem exercer o commit, caso haja uma falha durante fase 2.
O modelo relacional é schema-full. Isto significa que a estrutura das tabelas [colunas, datatypes e constraints] precisa estar definida antes dos dados serem gravados. É como um contrato entre quem vai ler e quem escrever no banco de dados.
A característica schema-full, as propriedades ACID, e o protocolo 2PC são os alicerces da integridade no sistema de banco de dados Relacional. Há outros acessórios [como as leituras consistentes e o MVCC] para melhorar a experiência do usuário diante da força bruta de consistência disponível.
Há Certas Coisas que os Sistemas Relacionais Não Fazem por Você
Os TRADE-OFFS mais importantes dos sistemas Relacionais são, em primeiro lugar, A FALTA DE FLEXIBILIDADE DO FORMATO DE DADOS, e depois, A BAIXA CAPACIDADE DE ESCALAR no nível da internet.
A FALTA DE FLEXIBILIDADE foi na verdade uma vantagem do modelo Relacional nos anos 80-90 [quando os desenvolvedores tinham que fazer o schema na mão]: o modelo de dados é schema-full. Isto é, primeiro é necessário criar a estrutura dos dados, para depois inserí-los, e não o oposto [como ocorrem com os NoSQL]. Há vantagens na abordagem schemaless, principalmente nos tempos atuais, e portanto, hoje, não tê-la é um ponto negativo [mais adiante eu falo sobre Multi-Model, que torna o sistema Relacional mais moderno].
A BAIXA CAPACIDADE DE ESCALAR ocorre porque, em geral, nos sistemas Relacionais, os dados das tabelas não são distribuídos entre servidores distintos e independentes [shared-nothing], e por isso eles apenas escalam verticalmente [até a capacidade de um servidor, e não de vários] – esse é um forte limitador de escalabilidade.
Há, entretanto, uma implementação de software ainda única, da Oracle [chamada Oracle RAC], que permite que vários servidores ativos e distintos acessem os arquivos de um mesmo banco de dados [shared-disk], mantendo a consistência forte. No teorema CAP que explico mais adiante, o RAC recebe a classificação CA [consistency e availability]: essa tecnologia é a que mais oferece escalabilidade para um sistema de banco de dados Relacional, mas ainda é inferior aos níveis de escalabilidade oferecidos pelos NoSQL.
VOCÊ DEVE CONSIDERAR O SISTEMA DE BANCO DE DADOS RELACIONAL PARA DADOS QUE PRECISAM DE INTEGRIDADE.
Os Sistemas NoSQL são como Albatrozes: Ágeis no Ar, mas Desajeitados em Terra
Apesar de tanta inovação e robustez para gerenciar dados, por causa da internet, o modelo de infraestrutura que só escala verticalmente [para cima], como ocorre com os bancos de dados Relacionais, demonstrou não atender a escalabilidade necessária para suportar aplicações web de OLTP intenso: milhões de usuários com demandas variáveis e imprevisíveis.
No ano 2000 surgiram as primeiras tecnologias NoSQL que ganharam escala. Fizeram muito sucesso como forma de persistência nas redes sociais, e começaram a ganhar espaço nas empresas.
Os bancos de dados NoSQL, de forma geral, são baseados em estruturas de dados schemaless, em arquitetura shared-nothing [totalmente distribuído, nada é compartilhado], e por isso conseguem escalar horizontalmente [para os lados] e armazenar qualquer estrutura de dados. Há muitas implementações de NoSQL, sendo que as principais são Chave-Valor, Documentos, Grafos e Orientado a Coluna.
A implementação Chave-Valor é indicada para leitura ou escrita intensiva de qualquer coisa, não importa o formato, desde que seja com o maior throughput possível. A implementação de Documentos é indicada para manipular informações que são agrupadas e relacionadas, como um catálogo de produtos, por exemplo. Grafos é indicada para dados altamente conectados, para encontrar conexões entre pessoas e coisas. Orientado a Coluna é um híbrido do formato linha e coluna, e é indicado para altos volumes de dados, em especial para escrita [não tanto para consulta].
Você precisa entender o Teorema CAP [Consistency, Availability, Partition Tolerance] e sua importância no mundo dos sistemas distribuídos. Ele prova que um sistema que distribui seus dados em servidores diferentes [sem compartilhar qualquer componente de infraestrutura], não pode ter disponibilidade e consistência ao mesmo tempo. No advento de uma falha na rede ou em um servidor qualquer, a CONSISTÊNCIA É GARANTIDA [letra C do CAP, onde um leitor enxerga todas as escritas completadas previamente], ou a DISPONIBILIDADE É GARANTIDA [letra A do CAP, onde o sistema sempre estará disponível para leitura/escrita], e não ambos.
Em geral, os sistemas NoSQL suportam AP [A de Availability, e P de Partition Tolerance]: sempre que há escrita em um servidor, ela é replicada de forma assíncrona para outros servidores espelho para manter a disponibilidade da informação – todos os servidores, os que escrevem, e os que recebem as escritas replicadas, ficam disponíveis para leitura.
Como exemplo, em uma configuração de cluster com 10 servidores, em geral 5 permitem escrita, e os outros 5 permitem apenas leitura. Nesta configuração, cada servidor-escritor replica de forma assíncrona para seu par que só permite leitura. Cada conjunto escritor/leitores são completamente independentes de outros conjuntos escritor/leitores, e cada um desses conjuntos armazena uma parte da informação.
Se houver falha em um servidor, os demais servidores espelho continuam lendo ou escrevendo, mesmo que possa haver inconsistência: a falha impede que um servidor replique seus dados para as outros servidores espelho. Desta forma, quando se lê um dado nesta situação, ele estará eventualmente consistente. Isso ocorre porque o dado poderá ter sido alterado, mas esta alteração pode não ter sido propagada para as réplicas. Além disso, mesmo sem uma falha, como as replicações são assíncronas, é possível que uma leitura em uma réplica possa não estar enxergando a versão mais recente da informação. Logo, haveria também uma leitura eventualmente consistente.
Ao contrário dos sistemas AP, os sistemas CP privilegiam a consistência forte. Um servidor-escritor envia os dados de forma síncrona para os seus respectivos servidores espelho. Então, se você está lendo a partir do servidor que escreve, ou da réplica, você sempre estará lendo a informação mais recente. Isso é consistência forte. Entretanto, se um servidor que escreve tem uma falha e fica indisponível, os seus pares ficam impossibilitados de escrever para evitar um cenário de inconsistência. Por isso, uma parte da informação torna-se inacessível, porém não o sistema todo: apenas os servidores com falha.
Esse é o trade-off entre AP e CP. E não é possível um sistema de banco de dados ter C, A e P ao mesmo tempo, conforme prova o teorema.
Tanto os sistemas AP, como os CP, dizem ter Consistência. Mas é importante entender que existem dois tipos de Consistência: a Forte, onde um leitor enxerga todas as escritas feitas previamente; e a Eventual, onde um leitor pode ou não, isto é, eventualmente, enxergar as escritas feitas previamente. Além disso, existe a Consistência no ACID, que tem a ver com integridade do dado escrito [datatypes, null ou not null, constraints, etc], e também existe a Consistência no CAP, que indica se a informação que um leitor lê é, ou não, a versão mais recente.
Consistência eventual para as redes sociais, ok! Para os batches… humm, talvez. Para as aplicações online? Complicado…! Neste caso, se necessário, o desenvolvedor que deve garantir a consistência forte em um sistema AP, já que ela não está disponível nesse tipo de banco de dados – e vale lembrar que é muito complexo codificar consistência: não é exatamente para qualquer um! É uma codificação altamente suscetível a bugs [lembra quando falei sobre as inovações do sistema Relacional? Os NoSQL descartam várias delas, a consistência forte é um exemplo].
Quanto mais os bancos de dados NoSQL se aproximam das aplicações online nas empresas, maior é a necessidade de transações, ACID, e consistência forte.
Não é exatamente uma desilução dos NoSQL que suportam AP, pois eles ainda têm seu lugar em diversos casos de uso. Mas está cada vez mais comum a introdução de capacidades CP [consistência] nas tecnologias que outrora iniciaram sua implementação com AP.
Um outro ponto relevante é que nenhum sistema garante efetivamente 100% de disponibilidade [o A do CAP]. Na prática há alguns 9s de disponibilidade, mas nunca 100% [você pode ter 20 réplicas, mas embora difícil, não é impossível perder todas elas]. Então o A do CAP é apenas “teórico”, mesmo para os NoSQL AP, que notadamente sacrificam a consistência para supostamente garantir 100% da disponibilidade. De fato, tanto a consistência quanto a disponibilidade são sacrificadas nos sistemas NoSQL AP.
E para complicar um pouco mais, AP sempre sacrifica a consistência, pois em virtude da necessidade de baixa latência [lê-se replicação assíncrona], os dados em geral sempre estarão eventualmente consistentes, mesmo sem uma falha ou falta de comunicação na rede.
VOCÊ DEVE CONSIDERAR UM SISTEMA DE BANCO DE DADOS NOSQL QUANDO ESCALABILIDADE FOR MUITO MAIS IMPORTANTE DO QUE INTEGRIDADE, DO CONTRÁRIO, CONSIDERE O RELACIONAL.
Obrigado pela Ajuda NoSQL: Agora é com a Gente!
A necessidade real nas empresas para atender as demandas de escalabilidade atuais é Consistência Forte [do SQL] com Escalabilidade Horizontal Distribuída [do NoSQL]. Eis então que surgem os bancos de dados NewSQL!
O título desta parte do meu artigo é originalmente do post de um blog do MemSQL, que faz uma sátira com os bancos de dados NoSQL, em favor do deles, um banco de dados NewSQL. E eles ainda completam: “Tá na hora de admitirmos o que todos nós já sabíamos por muito tempo: NoSQL é a ferramenta errada para muitos casos de usos nas aplicações modernas, e está na hora de seguirmos em frente.“
O texto do post começa explicando a ascensão da tecnologia NoSQL diante das supostas limitações da tecnologia SQL para os sistemas mais modernos, digitais e cloud native. Na sequência é introduzida a tecnologia NewSQL, que emerge dos pontos positivos do SQL e NoSQL combinados, o que acaba por colocar em decadência as tecnologias só-NoSQL, e também só-SQL.
De fato, SQL fez emergir NoSQL, que fez emergir NewSQL. E os sistemas NewSQL são então, mais do que nunca, gratos pela contribuição dos NoSQL, que os fez surgir, daí o título ligeiramente escrachado do post.
A diferença mais notável entre um NoSQL e um NewSQL é que o último suporta consistência forte, e na melhor da boa vontade, SQL e outras características do sistema Relacional. Os sistemas de informação nas empresas não são Facebooks, Instagrams, Twitters. Elas precisam de consistência. Então sim, NewSQL ascende. NoSQL, decai.
Os sistemas NewSQL representam uma evolução em relação aos NoSQL, oferecendo suporte a CP do CAP. NewSQL tenta ser um SQL, e tolera partições de rede, a grande diferença. A tolerância a partição permite escalar horizontalmente, como os NoSQL, e entrega escalabilidade ao nível da internet.
Mas francamente, quase todos os NewSQL, ou todos realmente, não suportam SQL plenamente. Não há como ignorar quase 4 décadas de desenvolvimento. Todos os NewSQL suportam apenas uma porção do que os sistemas SQL tradicionalmente suportam: compliance ao ANSI plenamente, extensões proprietárias, ACID, 2PC, Multi-Model, segurança abrangente de dentro pra fora, backups e restores granulares, monitoração robusta com grande poder de instrumentação, e milhares de outras características.
É apreciável o esforço de construir uma consistência nativa bem elaborada numa arquitetura dominada por Albatrozes que voam bem, mas pousam terrivelmente mal [aqui eu me refiro aos NoSQL].
VOCÊ DEVE CONSIDERAR UM SISTEMA DE BANCO DE DADOS NEWSQL QUANDO ESCALABILIDADE FOR MUITO RELEVANTE, TÃO QUANTO INTEGRIDADE, DO CONTRÁRIO, CONSIDERE ALGUM DOS ANTERIORES.
Não é um Pato, é Multi-Model
Os sistemas de banco de dados Multi-Model são aqueles que permitem nativamente vários formatos ao mesmo tempo, como Relacional, Grafos, Chave-valor, Documentos, Colunar e qualquer outro que se torne relevante.
A característica Multi-Model se torna relevante principalmente nos tempos atuais, onde as aplicações podem requerer persistência poliglota, isto é, um sistema de banco de dados diferente para cada parte da aplicação, já que cada um é melhor em algum caso específico.
A verdade é que sempre existe aquele sistema de banco de dados “cutting-edge“, de ponta, de última geração, crème de la crème. Aquele que só ele faz aquilo que ele faz. Mas o que também ocorre é que se aquilo que só ele faz se torna relevante, os sistemas de banco de dados multi-model o absorvem. Tem sido assim nos últimos anos, e provavelmente sempre será.
As inovações dos sistemas Single-Model são incorporadas nos sistemas Multi-Model
Desenvolver um banco de dados é muito complexo. Um exemplo disso é o bem difundido PostgreSQL [com suas limitações de escalabilidade], que fez por exemplo o Uber deixar de usá-lo, conforme mencionei no início deste artigo. É mais simples e rápido incorporar features novas do que construir todo um core, e é por isso que os sistemas de banco de dados Multi-Model ainda dominam.
VOCÊ DEVE CONSIDERAR UM SISTEMA DE BANCO DE DADOS MULTI-MODEL QUANDO FLEXIBILIDADE DE SCHEMA E CONSISTÊNCIA FOREM AMBOS MUITO IMPORTANTES.
Conhecer Python ou SQL para fazer data wrangling é igual gravidez: quanto antes você souber, melhor!
Boa parte do trabalho de um cientista de dados, e de um engenheiro de machine learning, é arrumar os dados. Você precisa organizar tudo antes de começar a explorar, e colocar os algoritmos pra máquina aprender.
Eu conheço SQL há muito tempo, e já fiz cada transformação que até a Álgebra Relacional dúvida!
Não é só a linguagem em si, mas o banco de dados também ajuda. Por exemplo, no Oracle você pode criar colunas virtuais, trocar partes da tabela com dados por partes sem dados, inserir em várias tabelas diferentes ao mesmo tempo em que lê a partir de uma query, utilizar funções PL/SQL que podem executar com paralelismo pipeline, persistir em vários formatos de dados, enfim, é uma miríade de capacidades de transformação, tanto para a performance, como para a funcionalidade.
Mais tarde eu aprendi como fazer essa arrumação com Python – já tendo conhecido outras linguagens, como Java por exemplo. Neste post vou comparar brevemente como é fazer esse trabalho de wrangling com SQL e Python [através de uma biblioteca com essa finalidade].
Definitivamente SQL e Python são as melhores ferramentas não-Nutella [sem o apoio de uma ferramenta de transformação própria pra isso] para limpar e arrumar dados.
Meu primeiro contato com Pandas ocorreu há mais ou menos um ano. Confesso que achei que estava re-construindo a roda. Praticamente tudo que eu fazia com essa biblioteca em Python eu acreditava que conseguia fazer em SQL com muito mais simplicidade. Bom, primeiro eu explico o que é o Pandas.
Pandas é uma biblioteca open-source em Python para análise de dados.
Pandas basicamente é composto por um objeto chamado Dataframe [uma planilha!], e este dispõe de vários métodos com uma boa usabilidade para manipular dados. Minha primeira impressão ao utilizar o dataframe foi a de utilizar o Excel em forma de código, mas com muito mais performance.
Para instalar, como todo pacote Python, basta executar o comando abaixo no sistema operacional [Terminal no Mac ou Linux, e Command Window no Windows]:
pip install pandas
Para utilizar, em um notebook [Jupyter ou Zeppelin] ou em um arquivo Python .py:
import pandas as pd
meuDataFrame = pd.read_csv('arquivo.csv')
meuDataFrame.describe()
O código acima importa o pacote Pandas, carrega um arquivo csv no dataframe meuDataFrame, e faz um describe nos dados. Describe() é fantástico! Ele retorna uma tabela com uma série de dados estatísticos para cada coluna, como count, avg, sum, stddev, min, max e percentis. Essa primeira exploração é bem interessante com Pandas em relação ao SQL. Mas a vantagem do Pandas começa e termina aqui. Quase que todo o resto do trabalho de wrangling [limpeza dos dados] eu achei muito mais simples e mais rápido com SQL, por isso a sensação de estar reinventando a roda.
Limpar e transformar dados sobre grandes volumes requer critério. Cada minuto pensando na estratégia de implementação equivale a horas de processamento.
A manipulação dos dados em si com dataframes consiste em criar dataframes a partir de dataframes, sendo que as cópias vão transformando os dados aos poucos, com colunas novas a mais, ou a menos. Há também agregações [groupby], filtros [query], unicidade [unique], ordenações [sort_values], e merges e joins [este último me lembra…. SQL!]. É necessário registrar também que há uma miríade de funções estatísticas para utilizar que são bem interessantes.
Em Python com Pandas:
# Adicionar nova coluna somando 10 sobre uma coluna existente
meuDataFrame['nova_coluna'] = meuDataFrame['col1'] + 10
# Somar
meuDataFrame.col1.sum()
# Filtrar coluna maior que 100
meuDataFrame.query('(col1 > 100)')
# Eliminar duplicidade
meuDataFrame.col1.unique()
# Ordenar
meuDataFrame.sort_values(by='col1', ascending=False)
Em SQL:
# Adicionar nova coluna somando 10 sobre uma coluna existente
SELECT a.*, a.col1 + 10 as nova_coluna FROM tab a
# Somar
SELECT SUM(col1) FROM tab
# Filtrar coluna maior que 100
SELECT * FROM tab WHERE col1 > 100
# Eliminar duplicidade
SELECT DISTINCT col1 FROM tab
# Ordenar
SELECT * FROM tab ORDER BY col1 DESC
Pandas tem também uma excelente integração com o pacote Numpy para processamento de arrays e matrizes multidimencionais, e o Matplotlib, para visualização de gráficos
Pandas é facil, mas SQL é mais human-readable, na minha opinião. Com SQL a manipulação de dados é extremamente trivial. Ao invés de criar dataframes a partir de outros dataframes para incluir, transformar ou remover colunas, você faz subquery ou transforma na própria cláusula SELECT. Todas as APIs que você pode imaginar para trabalhar um dado existem nos sistemas gerenciadores de banco de dados que suportam o SQL ANSI. Desde funções descritivas simples, como SUM ou COUNT, até funções mais complexas como as Regressões Lineares, Testes de Hipótese e Análises de Variância. Adicionalmente, existem também as funções analíticas [esta última me lembra… Pandas!] e as de machine learning. Com Pandas, bom, para machine learning, teria que utilizar algum outro pacote [como scikit-learn, por exemplo].
Uma Conversa Franca sobre Não Perder Tempo
No final do dia eu prefiro SQL, mas depende.
Eu prefiro Pandas quando manipulo arquivos que não precisam persistir por muito tempo [análises pontuais] e não precisam de integração com outras fontes de dados, e não precisa de tanta performance.
Por exemplo: costumo fazer análises de infraestrutura com centenas de servidores, cada um com centenas métricas, e depois de tomar as conclusões, apago tudo – criar um banco, criar as tabelas, carregar os dados, e só então explorar os dados leva tempo… é melhor fazer esse tipo de análise com Pandas.
Quando preciso de um acabamento mais enterprise, isto é, algo que vai existir por mais tempo, com grande volume de dados, que vai ser utilizado por outras pessoas, que será reutilizado, compartilhado, que precisa de segurança, e claro, extrema performance e escalabilidade, não há dúvidas que SQL, na minha opinião, é melhor.
Tente conhecer os dois: SQL e Pandas. Use Pandas quando for mais conveniente, do contrário use SQL. Você escala mais conhecendo ambos.