Show HN: LearnDB — um RDBMS (clone do SQLite) implementado do zero em Python puro
(github.com/spandanb)- O LearnDB é um sistema de gerenciamento de banco de dados relacional (RDBMS) e clone do SQLite implementado do zero para entender mais a fundo a estrutura interna de bancos de dados
- Escrito em Python puro, não tem etapa de build e, por padrão, é zero configuração, com uma estrutura que permite sobrescrever configurações
- Oferece o learndb-sql, com suporte a
select,from,where,group by,having,limiteorder by, além de um lexer e parser personalizados baseados nolark - É composto por um mecanismo que recebe instruções SQL e manipula as tabelas e os dados do banco, além de uma estrutura de dados de backup btree baseada em disco
- Pode ser usado via REPL, importando como módulo Python ou passando arquivos de comandos ao mecanismo
- A base de código é adequada para tinkering, mas tem limitações importantes que impedem seu uso como solução real de armazenamento
- A aritmética de ponto flutuante é uma implementação bastante simplificada em comparação com IEEE754
- Não oferece suporte a funcionalidades utilitárias comuns, como expansão de colunas por curinga em
select * ...
- Os requisitos para execução em desenvolvimento são um sistema Linux/macOS e Python 3.9 ou superior; usa
fcntlpara acesso exclusivo de leitura ao arquivo de banco de dados - Como referências, usa o tutorial de banco de dados da cstack, SQLite Database System: Design and Implementation, a documentação do formato de arquivo do SQLite e a documentação do PostgreSQL
1 comentários
Opiniões no Hacker News
Acho que escrever um sistema desses em uma linguagem como Python é, na verdade, uma excelente escolha. Bancos de dados normalmente são escritos em C++ ou C, mas, para mim, Python é muito mais legível e acessível
Se a ideia for mirar seriamente em desempenho, dá para portar depois para uma linguagem de baixo nível; no formato atual, ele é útil para aprendizado
Eu também criei em Python um banco de dados distribuído meio multimodelo, misturando SQL/grafo Cypher/documentos/estilo DynamoDB, para aprender como um motor de banco de dados pode funcionar em ambientes distribuídos: https://GitHub.com/samsquire/hash-db
Tanto C quanto Python parecem acessíveis quando você ignora design ruim da linguagem, inconsistências, várias armadilhas e olha só para as partes fáceis. Mas com C pelo menos há alguma chance de aprender o jeito certo de fazer; com Python, você talvez nem chegue a saber como é o mundo real
Há muito tempo, alguém reescreveu/portou o SQLite de C para C#: https://code.google.com/archive/p/csharp-sqlite/wikis/Letter...
Também vale ver o quanto o Dr. Richard Hipp recebeu bem esse trabalho
No GitHub, provavelmente está aqui: https://github.com/CsharpDatabase/CsharpSQLite e talvez existam outros clones posteriores
Excelente. Com certeza deve ter sido uma experiência divertida e recompensadora
Sei que a intenção não era fazer algo rápido, mas, por diversão, será que daria para criar alguns benchmarks?
Graças a este post, descobri uma biblioteca de parser para Python chamada Lark, que parece bem boa
O tutorial de JSON no site é excelente. Ele mostra como criar um parser básico para JSON e depois aborda, com bastante detalhe, como melhorar o desempenho: https://lark-parser.readthedocs.io/en/latest/json_tutorial.h...
A gramática usada no projeto de RDBMS está aqui: https://github.com/spandanb/learndb-py/blob/master/learndb/l...
Ao depurar gramáticas, a IDE foi muito útil: https://www.lark-parser.org/ide/
No EvaDB, usamos Lark para uma linguagem semelhante a SQL voltada ao uso de modelos de IA: https://github.com/georgia-tech-db/evadb/blob/master/evadb/p... https://github.com/georgia-tech-db/evadb/
Se você gosta do Lark, vale considerar apoiá-lo: https://github.com/sponsors/lark-parser
Só usar um dict com as chaves esperadas e composição por meio do operador OR bit a bit já não se encaixaria mais ou menos em muitas formas de gramática e seria melhor? Os imports poderiam continuar como imports, e acho que daria para misturar de alguma forma
É só a primeira impressão de uma olhada rápida, então posso estar deixando passar alguma coisa
Existe uma parte que precisa continuar sendo otimizada para tornar o parser gerado mais eficiente?
O próximo passo lógico seria gerar, a partir da AST, o plano de consulta ideal?
Muito bom
O SQLite é muito difícil de ler, mas esta implementação é bem fácil de entender. Especialmente a parte da máquina virtual: https://github.com/spandanb/learndb-py/blob/master/learndb/v...
Dá para comparar com este arquivo: https://github.com/sqlite/sqlite/blob/master/src/vdbe.c
Mas fico curioso para saber o quão completo é este LearnDB. O SQLite é difícil de ler não só porque é antigo, mas também porque lida com muitas partes do SQL e acaba ficando complexo ao seguir a especificação do SQL
O SQLite tem uma excelente suíte de testes; seria interessante rodá-la nesta implementação
Muito bom mesmo, e parece uma boa forma de alguém como eu aprender melhor estruturas de dados e algoritmos. Consigo explicar como uma B+tree funciona, mas acho que travaria se me pedissem para programar uma do zero
Gosto de bancos de dados e de Python, então foi realmente interessante dar uma olhada
Além disso, o fato de ser uma estrutura armazenada em disco acrescentou mais uma camada de complexidade ao pensar na implementação
Quanto da suíte de testes do SQLite será que ele consegue passar?
Ele oferece suporte a garantias ACID ou a planejamento/otimização de consultas?
Não estou perguntando no sentido de que deveria ter isso; só quero saber até onde você tentou ir além de B-tree e SQL
Eu também gostaria de fazer algo assim algum dia. Belo trabalho
Mas, fora isso, é um banco de dados de arquivo único, e apenas uma instância do learndb pode manipular o arquivo do banco de dados. Então, por ser um banco de dados de conexão única, você obtém consistência e isolamento
A durabilidade existe na medida em que o sistema de arquivos oferece durabilidade. Então ele fica em algum ponto dentro das propriedades ACID
Planejamento/otimização de consultas ainda não foi implementado, mas já pensei onde um módulo de otimização poderia entrar. O parser emite uma AST, e essa AST, ou uma representação intermediária derivada dela, poderia ser otimizada
Ou seja, antes de a VM executar a AST, ela poderia reescrever a AST ou remover nós
Fugindo um pouco do assunto, existe algo como mapDB em Python?
https://mapdb.org
Projeto excelente. O código também é muito legível, e os comentários são ótimos