Durante o desenvolvimento de uma aplicação, seja ela web, desktop ou mesmo mobile, sempre aparece algumas perguntas...complexas. Que linguagem de programação usar? Framework? Quais plataformas focar? E mais importante ainda: Onde armazenar os dados da aplicação?
Naturalmente, as resposta vão variar bastante de aplicação para aplicação. Não existe sequer uma aplicação em que eu trabalhei na vida em que a resposta foi simplesmente "evidentemente vai ser X, pois sim", embora com o passar dos anos a experiência e o conhecimento sobre diferentes soluções ajude na decisão por escolhas melhores e mais apropriadas para cada contexto.
E hoje, depois de anos sem escrever nada por aqui, eu vou falar um pouco sobre uma forma de armazenar e consultar dados que é bem interessante, mas quase nunca considerada no desenvolvimento de uma aplicação moderna, embora seja literalmente o mecanismo de banco de dados mais usado do mundo (sim, eu sei que isso é bastante contra intuitivo, mas eu já vou explicar mais sobre): o SQLite.
O que é
O SQLite é uma biblioteca desenvolvida na linguagem C por D. Richard Hipp lançada em 17 de agosto de 2000 enquanto Richard trabalhava para a General Dynamics em um contrato com a marinha dos Estados Unidos.
A ideia principal da biblioteca é bem simples: Prover uma forma de armazenar e consultar dados de forma confiável, com o uso de SQL, mas sem precisar dos complicados processos de instalação e manutenção que um sistema de gerenciamento de banco de dados (SGBDs) necessita, mas sem deixar a desejar muito em recursos, ao mesmo tempo que evita a necessidade de um administrador de banco de dados (ou DBA, como também é conhecido).
Apesar disso, e de conter uma série de recursos que normalmente são encontrados em SGBDs - como suporte a múltiplas tabelas, views, índices (até mesmo full-text!) e até mesmo triggers - o SQLite não compete contra esses sistemas gerenciadores de bancos de dados. Em vez disso, o SQLite compete com o....fopen(). Sim, a mesma chamada padrão que permite que você abra e crie arquivos.
Onde é usado
O SQLite é usado em praticamente...todo lugar. Seu navegador, esse que você provavelmente está usando agora para ler este post, usa SQLite. O seu sistema operacional, seja ele o Windows, Linux (nesse caso, muitas vezes, a nível de distribuição) ou Mac, usa SQLite.
Seu smartphone - e muitos dos aplicativos que você tem instalado nele - usam SQLite (o Android e o iOS chegam até mesmo a oferecer o SQLite de forma nativa). Além disso, muitos dispositivos inteligentes hoje, incluindo as Smart TVs e até muitas geladeiras inteligentes (daquelas super caras), chegam a usar SQLite.
Fora da sua casa, existem sistemas multimídias de carros e até mesmo aviões que usam SQLite, e muitas vezes ele é incluído nos ambientes nativos de linguagens de programação....populares, como PHP e Python. Legal, né?
Casos de Uso Úteis
Como você já pode perceber, o SQLite é um mecanismo de bancos de dados versátil, e na prática, você pode usá-lo em praticamente qualquer situação onde você deseja persistir dados.
Claro, isso não significa que seria uma decisão super inteligente fazer um mecanismo de busca com o objetivo de rastrear quase toda a internet como o Google faz apenas em cima de um banco de dados salvo pelo SQLite, ou então, criar um site que vá receber milhares de visitas por segundo, mas...veja: Em que momentos você precisa fazer isso, mesmo?
Por exemplo, quais aplicações precisam trabalhar com uma quantidade tão absurda de dados, enquanto as consulta tão frequentemente por dia? Pois é, não são muitas. Claro, não vou dizer que dá pra contar nos dedos, pois existem bastante situações em que a quantidade de dados é realmente grande, e a necessidade por fazer consultas frequentes também, mas, dá para dizer com tranquilidade que, para uma grande maior parte dos projetos por aí, o SQLite é sim uma opção bastante viável.
Com isso dito, na minha experiência, o SQLite se mostra especialmente valioso na criação de scripts, desses que são criados para processamento de dados. Isso porquê, com o SQLite, você consegue não só organizar os dados em uma estrutura conhecida, como também consultá-los de maneira eficiente. Chega num ponto em que fica tão interessante que você simplesmente consegue parar o script em dado ponto e rodar consultas para verificar se os dados estão sendo salvos da maneira como você esperava. É algo com MUITO potencial.
Uma outra situação em que o SQLite se destaca é no desenvolvimento de protótipos. Afinal, para quê usar um SGBD complexo rodando 24/7 somente para o desenvolvimento de um simples MVP que a principio vai rodar só na sua máquina, por exemplo? Para esses casos, a simplicidade do SQLite ajuda a economizar muito tempo que em outra situação seria gasto instalando e configurando um SGBD como o MySQL ou o PostgreSQL, por exemplo.
Outra situação no qual o SQLite se destaca bastante é para análise de dados, graças ao uso de ferramentas incríveis como o Datasette, que possui um ecossistema rico de plugins afim de ajudar na análise de diferentes tipos de dados e na criação de diferentes visualizações, como dashboards, só para citar um exemplo.
Por fim, uma outra situação no qual o SQLite é normalmente considerado é para o desenvolvimento de testes de integração - onde muitas aplicações acabam precisando se comunicar com o banco de dados afim de poder rodar suas consultas. Honestamente, eu não sugeriria fazer isso a menos que o seu SGBD principal já seja o SQLite, visto que muitas consultas podem acabar funcionando de forma diferente no SQLite vs. no seu SBGD principal. Apesar disso, é algo que ainda é bastante considerado e difundido na internet, logo fica aqui o aviso.
Para entender melhor em que situações vale considerar seu uso, vamos falar um pouco sobre suas vantagens e desvantagens.
Vantagens e Desvantagens
Apesar do fato do SQLite tentar competir mais com o fopen(), sua lista de vantagens e desvantagens na realidade é bem..interessante, em especial se você considerar quão pequeno o SQLite de fato é (a biblioteca compilada pesa menos de 1MB). Nessa seção, vou abordar alguns pontos que podem tanto motivar quanto desmotivar a escolha pelo SQLite.
Vantagens
Existem várias vantagens em usar o SQLite. Naturalmente, mesmo que alguma vantagem lhe pareça extremamente conveniente, isso não significa que ele será a solução absolutamente PERFEITA para o seu caso de uso. Afinal, vale dar uma olhada na lista de desvantagens também, afim de evitar eventuais problemas futuros. =)
Dito isso, vamos às vantagens:
Serverless (não precisa de servidor)
O SQLite é um SGBD que não necessita de configuração e inicialização de servidores. Basicamente, você importa/linka o SQLite no código do seu projeto, chama as funções da API pública para criar/abrir o banco de dados, rodar consultas e afins, e...é isso.
É basicamente como se, de repente, o driver que você usa para conectar ao banco de dados fosse de fato o banco de dados por si só, com latência basicamente zero, e sem a necessidade de fazer mais nada além do que você já está acostumado a fazer, que é chamar a API pública para abrir o banco de dados, rodar as migrações da sua aplicação para preparar a estrutura do banco de dados, e executar consultas.
Naturalmente, isso pode levar a alguns erros que não acho que aconteceriam tão facilmente no caso de um servidor de banco de dados. Se você passar a string ":memory:" como nome do banco de dados que você quer abrir, por exemplo, o SQLite vai abrir um banco de dados somente em memória, que portanto vai ser destruído no momento que a aplicação for encerrada. Da mesma forma, se você passar uma string vazia, o SQLite vai abrir um banco de dados em uma pasta temporária, que também será apagada ao final da execução do programa, mas que não é mais limitada pela quantidade de memória RAM disponível.
Portátil
Como é possível perceber, o SQLite opera manipulando diretamente arquivos locais de banco de dados. Isso significa que ele não exige nenhuma configuração e gerenciamento de portas nem nada do tipo, sendo, portanto, portátil. Se você desenvolve uma aplicação que usa SQLite e que salva o arquivo em um diretório na mesma pasta, por exemplo, você pode fazer operações no banco de dados mesmo de um pendrive, o que mostra o quão portátil é o SQLite enquanto banco de dados.
Confiável
O SQLite é extremamente confiável, ao ponto que consegue ser o mais resiliente possível mesmo para erros de sistema ou de memória. Além disso, também é resistente contra arquivos maliciosamente alterados, e é recomendado pela biblitoeca do congresso dos Estados Unidos para armazenamento de dados a longo prazo.
Inclusive, falando em longo prazo, o time do SQLite planeja suportar o projeto PELO MENOS até 2050. Dado a quantidade enorme e variada de casos de uso do projeto, eu pessoalmente acredito que irá facilmente além dessa marca, mas isso mostra o quão confiável é o SQLite no geral.
Possui amplo suporte à muitos dos recursos encontrados em outros SGBDs relacionais
O SQLite possui suporte à praticamente todos os recursos que você espera de um SGBD convencional:
- Transações;
- JOINs;
- Window Functions - excelentes para analytics;
- Suporte a variados tipos de Índices, incluindo aí índices geográficos e full-text;
- Uma grande quantidade de funções para utilização nas consultas;
- Tabelas virtuais;
- Sub-Queries;
- Um planejador de consultas (query planner) bastante avançado e inteligente;
E vários outros recursos dignos de SGBDs avançados, como o PostgreSQL e o MySQL.
Possui um extenso ecossistema
O SQLite possui uma comunidade muito grande, pelo fato de ser um projeto extremamente usado. Isso faz com que o projeto tenha, também, um rico ecossistema, capaz de suprir as mais variadas necessidades dos seus usuários, a partir do uso de projetos que foram criados justamente para...atender problemas de outros usuários.
Uma lista bastante completa dos projetos ao qual me refiro está presente no repositório awesome-sqlite, mas aqui segue alguns que definitivamente chamam minha atenção:
- RQLite - Para usar o SQLIte com replicação entre diversos servidores, e também de forma mais tradicional, como um servidor à parte;
- LiteStream - Também para replicação de diferentes bancos de dados, só que agora sem necessidade do uso de um servidor à parte;
- Spatialite - Para estender o SQLite com habilidades geoespaciais, permitindo consultas capazes de lidar com dados geográficos de maneira muito eficiente;
Desvantagens
Como todo projeto e coisa nesse universo, o SQLite não é perfeito, e também tem sua lista de desvantagens própria, ou seja, não é uma solução que atende a todos os projetos de maneira absolutamente perfeita (se é que isso existe), e portanto é importante estar ciente de todos os possíveis problemas ao usar o projeto.
É mais dificil de escalar horizontalmente se usado em aplicações web
O SQLite, como já explicado nesse post, é basicamente uma biblioteca que se integra diretamente na aplicação, e que trabalha alterando diretamente um arquivo especificado, que é, nesse caso, o próprio arquivo do banco de dados (onde os dados e estruturas são efetivamente salvos).
Como pode-se imaginar, essa característica reduz significantemente a latência envolvida, pois a aplicação não precisa criar a consulta, mandar para um servidor, esperar o servidor processar e então receber a resposta para retornar para o usuário. Entretanto, essa abordagem também limita significantemente a capacidade de escalar horizontalmente de maneira fácil.
O que seria escalar horizontalmente, nesse caso? Simples! Imagine uma aplicação web, como um...blog, por exemplo. Numa arquitetura em que o SGBD é acessado usando o tradicional cliente-servidor, você pode ter vários clientes e um servidor. Ou seja, é possível ter 5, 10 máquinas distintas rodando o Apache/NGINX+PHP/Python/Go/qualquer outra linguagem, e apenas um banco de dados. Isso trás benefícios significativos quando os dados são apenas lidos do SGBD, e portanto é uma abordagem simples e muito utilizada para escalar aplicações web.
Entretanto, pela natureza do SQLite, isso...não se torna possível de maneira simples. Ou seja, você consegue, sim, escalar horizontalmente uma aplicação web usando SQLite (mesmo usando um dos projetos mencionados acima, como RQLite ou LiteStream), mas isso certamente será mais díficil do que em um SGBD cliente-servidor já pensado para atender esse tipo de situação.
Não possui suporte à concorrência em escritas
Outro problema característico do SQLite é a falta de suporte para atender grandes quantidades de usuários escrevendo simultaneamente no banco de dados. O que é uma grande quantidade, nesse contexto? Essa é uma boa pergunta! E a resposta para essa pergunta vai variar muito de acordo com a sua aplicação, as requisições feitas, e também a máquina no qual o código está rodando (por exemplo, se você salvar o arquivo do banco de dados em um HD, a performance vai ser MUITO pior do que se o arquivo estivesse em um SSD, naturalmente).
No geral, o que quero dizer aqui é que o SQLite acaba não sendo a opção mais adequada em um cenário com mais de uma operação de escrita sendo realizada em um dado momento. No modo padrão, por exemplo, o SQLite literalmente bloqueia todo e qualquer acesso ao banco de dados quando uma operação de escrita é realizada. Já no modo WAL (de Write-Ahead Logging, ou registro de gravação antecipada em tradução livre), o SQLite até permite que operações de leituras continuem sendo feitas, mas..adivinha? Demais operações de escritas ainda são bloqueadas.
Note que esses bloqueios acontecem mesmo em tabelas diferentes, e mesmo que as operações de escrita em questão não afetem ou sejam relacionados à outros registros no banco de dados. Por exemplo, se você tiver uma tabela simples de log, onde você só salva uma mensagem e a data do registro, a limitação ainda irá se aplicar.
Mas, isso dito, seria essa um problema que persistirá para sempre? Bom, não necessariamente. O próprio projeto do SQLite tem branches (similares às do GIT) onde os desenvolvedores do projeto estão estudando formas de solucionar esse problema e permitir mais de uma operação de escrita em um dado momento do tempo. Um grande exemplo de branch assim é a do BEGIN CONCURRENT, que basicamente implementa uma forma de permitir mais de uma transação de escrita ao mesmo tempo, ao procurar realizar bloqueios apenas quando duas operações manipulam exatamente o mesmo conjunto de dados.
Entretanto, HOJE, no momento em que escrevo esse post, essa branch ainda não foi mergeada na branch principal do projeto, e portanto, não há muitas alternativas para você, caro desenvolvedor, que quer escrever aplicações intensivas em escritas e que usem o SQLite, a não ser...solucionar o problema por conta própria.
Como? Bom, aí que as coisas ficam complicadas.. Você pode, por exemplo, implementtar em sua aplicação um sistema similar ao sharding de banco de dados, que consistiria, nesse caso, em ter vários arquivos de banco de dados, todos com a exata mesma estrutura, e fazer as operações de acordo com divisões que façam sentido para sua aplicação.
No exemplo do log, mencionado acima, você poderia criar um número arbitrário de arquivos de bancos de dados e, a cada operação de escrita, escrever em um dos arquivos de forma...aleatória (ou seja, se você tem 10 arquivos, você sorteia um e escreve nele). Está precisando de mais concorrência? Basta criar um número maior de arquivos, e aí o céu é o limite. =)
Ouuuu...você pode tomar a decisão lógica mais simples e.. optar por outro SGBD. Em um mundo em que temos SGBDs excelentes como o PostgreSQL à disposição, não tem muito motivo para você precisar fazer esse tipo de coisa na sua aplicação apenas por desejar usar o SQLite.
Conclusão
Como você pôde ver ao longo desse artigo, o SQLite é um SGBD extremamente versátil, portátil e fácil de usar. Claro, como toda e qualquer coisa por aí, o projeto tem seus pontos negativos, o que naturalmente pode ser um fator limitante para seu uso em tudo que é lugar.
Entretanto, é importante reconhecer o impacto que o projeto tem no mundo moderno, com o projeto sendo usado nos mais variados dispositivos e aplicações usados pelas pessoas, seja em um navegador de internet, seja em um sistema de um avião.
Deixe nos comentários o que você achou sobre esse artigo e também sugestões para os próximos! Eu pretendo voltar a escrever para o blog mais frequentemente - se tudo der certo - então ter ideias para cobrir aqui é legal e bem vindo! Valeu!
Deixe um comentário