Esse é o primeiro projeto que publico aqui no blog. Ainda não tem todo o nível de detalhe que eu quero ter nos próximos posts, mas achei interessante o suficiente pra servir como artigo inaugural.
A história é simples: eu estava acompanhando um módulo do meu MBA em Data Science e, no meio das aulas, apareceu aquela discussão clássica sobre qual ferramenta usar pra trabalhar com dados tabulares. Pandas, Polars, DuckDB — cada uma com seus fãs e seus motivos. Aí veio a coceira: em vez de ficar só no achismo, por que não medir?
Decidi começar pelo básico, a operação mais comum de todas: ler um arquivo CSV grande. Queria entender quanto de RAM cada ferramenta consome, quanto tempo leva e onde cada uma começa a sofrer. Analisei quatro arquivos CSV com tamanhos reais de 156 MB, 780 MB, 1.597 MB e 4.789 MB em disco. Para cada ferramenta, rodei o mesmo script de benchmark e registrei tempo de execução, pico de RAM, razão RAM/disco e throughput. Sem filtros, sem agregações, sem nada depois da leitura: só ler o arquivo e medir o que acontece na memória.
Parece pouco, mas em arquivos grandes a leitura já é onde a coisa começa a desandar. Então, pra começar, vamos dar uma olhada em como ficou o tempo de execução. Se liga aqui no gráfico.
Esse gráfico mede quanto tempo cada ferramenta levou pra carregar o CSV do início ao fim. O Polars foi muito mais rápido nos três primeiros arquivos. No arquivo de 1.597 MB, por exemplo, ele terminou em 1,47s, enquanto o Pandas levou 18,10s — mais de 12 vezes mais lento.
No maior arquivo aconteceu uma coisa meio engraçada, no sentido trágico da computação doméstica: eu tinha mais ou menos 10 GB de RAM livre pra fazer esse teste e não foi suficiente. Meu PC tem 16 GB de RAM, e a gente sabe o quanto RAM está cara hoje. Eu estava acompanhando pelo btop++, vi a memória acabar, o mouse começou a travar, o VS Code travou junto e eu tive que reiniciar a máquina.
Então eu não sei exatamente quanto tempo o Pandas levaria no arquivo maior. Se você tiver mais RAM e quiser brincar com isso, pega uns arquivos grandes e testa. Aqui, a comparação real ficou entre Polars e DuckDB, com os dois chegando ali perto de 22 a 24 segundos.
O próximo gráfico interessante é o pico de RAM utilizado. O nome é meio autoexplicativo, mas ele é importante porque mostra onde a leitura começa a bater no limite físico da máquina.
Aqui a ideia é registrar o maior uso de memória observado enquanto cada ferramenta lia o arquivo. Todas consumiram mais RAM do que o tamanho em disco, porque o parser precisa de espaço extra para montar as estruturas internas.
No arquivo de quase 4,8 GB, o DuckDB chegou a quase 10 GB de RAM no pico. O Polars ficou em 8.697 MB. Já o Pandas, infelizmente, eu não consegui medir até o fim. Como eu disse, eu tinha cerca de 10 GB livres e não teve como: estourou. Provavelmente ficaria acima disso, talvez perto de 12 GB, mas isso aqui já entra como leitura minha, não como número medido.
Outra coisa interessante de olhar é a razão RAM/disco. Ela ajuda a sair do “será que cabe?” e transformar isso em uma conta mais concreta antes de rodar o script.
Esse gráfico divide o pico de RAM pelo tamanho real do arquivo em disco. É um multiplicador: mostra quantas vezes a ferramenta precisa de memória além do tamanho do arquivo.
Todos ficaram perto de 2x nos arquivos intermediários. Na prática, isso significa que pra ler um CSV de quase 5 GB você precisa ter pelo menos 9 a 10 GB de RAM disponível. Saber essa razão antes de rodar evita surpresa no meio do script. E deixando claro: o Pandas provavelmente tenderia a subir também no arquivo maior, mas como ele não concluiu, eu não tenho esse ponto medido no gráfico.
E aí temos o throughput em MB/s, que é uma forma rápida de enxergar quantos megabytes por segundo cada ferramenta conseguiu processar.
Esse número é calculado dividindo o tamanho do arquivo pelo tempo de leitura. O Polars dispara aqui: passa de 1.000 MB/s nos arquivos intermediários e fica muito acima do Pandas nos testes que o Pandas conseguiu concluir.
Pra quem não conhece, o Polars é escrito em Rust e tem uma arquitetura bem voltada pra eficiência e paralelismo. O DuckDB é um banco analítico escrito em C++, também muito forte pra esse tipo de trabalho. Já o Pandas é uma biblioteca Python com muita coisa otimizada por baixo em C e Cython, mas carrega um modelo mais antigo e nem sempre brilha quando o arquivo começa a ficar grande.
No maior arquivo, o throughput do Polars cai bastante, provavelmente por pressão de memória, mas ainda fica levemente acima do DuckDB. O Pandas, além de consumir muita memória, ficou bem mais lento nos arquivos que concluiu.
E aqui fica a tabelinha com todos os dados brutos, do jeito que saíram do benchmark. Ela é útil pra conferir cada número sem depender só da leitura visual dos gráficos.
| Ferramenta | Arquivo | Tamanho real | Pico RAM | Tempo | RAM/Disco | Throughput |
|---|---|---|---|---|---|---|
| Pandas | Arquivo 1 | 156 MB | 340 MB | 2,20s | 2,18x | 71 MB/s |
| Pandas | Arquivo 2 | 780 MB | 1.631 MB | 9,45s | 2,09x | 83 MB/s |
| Pandas | Arquivo 3 | 1.597 MB | 3.342 MB | 18,10s | 2,09x | 88 MB/s |
| Pandas | Arquivo 4 | 4.789 MB | FALHOU | - | - | - |
| Polars | Arquivo 1 | 156 MB | 281 MB | 0,29s | 1,80x | 538 MB/s |
| Polars | Arquivo 2 | 780 MB | 1.571 MB | 0,73s | 2,01x | 1.068 MB/s |
| Polars | Arquivo 3 | 1.597 MB | 3.251 MB | 1,47s | 2,04x | 1.086 MB/s |
| Polars | Arquivo 4 | 4.789 MB | 8.697 MB | 22,50s | 1,82x | 213 MB/s |
| DuckDB | Arquivo 1 | 156 MB | 406 MB | 1,31s | 2,60x | 119 MB/s |
| DuckDB | Arquivo 2 | 780 MB | 1.487 MB | 4,15s | 1,91x | 188 MB/s |
| DuckDB | Arquivo 3 | 1.597 MB | 3.369 MB | 8,55s | 2,11x | 187 MB/s |
| DuckDB | Arquivo 4 | 4.789 MB | 9.894 MB | 24,21s | 2,07x | 198 MB/s |
Olhando tudo junto, dá pra ver que o problema não é só “qual biblioteca é mais rápida”. É também quanto de memória ela pede, como ela escala conforme o arquivo cresce e se ela continua confortável quando o dataset começa a encostar no limite da máquina.
O que eu concluo com esse primeiro recorte: Polars quando velocidade importa, isso ficou bem claro. DuckDB quando eu quero SQL e previsibilidade em arquivo grande. E Pandas quando o arquivo ainda cabe com folga na RAM ou quando o ecossistema ao redor pesa mais que performance.
Como esse foi um projeto relativamente antigo, eu não lembro todos os pormenores da execução, então preferi não inventar detalhe que eu não tenho registrado. O que está aqui é o que eu medi e o que aconteceu na prática. E esse teste foi só leitura. Ainda dá pra testar filtros, agregações, joins, escrita, tudo isso. Mas só esse pedaço já mostra uma coisa: em dados grandes, escolher biblioteca sem medir é apostar RAM no escuro.
E cuidado ao tentarem isso em casa, meus caros cavaleiros. Se a máquina não tiver RAM sobrando, pode acontecer igual aconteceu comigo: travar tudo e ter que reiniciar o PC. Eu já rodei o teste meio esperando que isso pudesse acontecer, mas se tivesse algo importante aberto na hora, teria sido uma dor de cabeça bonita.
É isso. Esse foi o primeiro artigo do blog, e a ideia é continuar trazendo esse tipo de experimento por aqui. Eu sempre fiz essas coisas mais sozinho, meio no meu canto; agora a graça é usar esse espaço pra trocar uma ideia e compartilhar um pouco do processo também.
