Python e DuckDB: Análise de Dados Ultrarrápida — 2026 | python.dev.br
Aprenda a usar DuckDB com Python para análise de dados local ultrarrápida. SQL direto em Pandas, Parquet e CSV sem servidor — exemplos práticos.
Se você trabalha com análise de dados em Python, provavelmente já passou por situações em que o Pandas ficava lento demais para datasets grandes, mas subir um banco de dados completo parecia exagero. É exatamente nesse espaço que o DuckDB brilha — um banco de dados analítico embutido, sem servidor, que roda SQL diretamente em arquivos CSV, Parquet e até DataFrames do Pandas.
Neste artigo, vamos explorar como usar DuckDB com Python, desde a instalação até consultas avançadas, com exemplos práticos para o dia a dia.
O Que É o DuckDB
O DuckDB é um banco de dados OLAP (Online Analytical Processing) embutido, projetado para cargas de trabalho analíticas. Pense nele como o “SQLite para analytics” — não precisa de servidor, não precisa de configuração, e roda dentro do seu processo Python.
As principais características do DuckDB:
- Zero configuração — não precisa instalar servidor, criar usuários ou configurar portas
- SQL completo — suporte a window functions, CTEs, subqueries e agregações complexas
- Integração nativa com Python — lê DataFrames do Pandas e Polars diretamente
- Leitura direta de arquivos — CSV, Parquet, JSON e até arquivos remotos via HTTP
- Performance absurda — processamento colunar vetorizado, muito mais rápido que Pandas para agregações
Instalação e Primeiros Passos
A instalação é simples com pip ou uv:
# Instalação
# pip install duckdb
# ou com uv:
# uv pip install duckdb
import duckdb
# Criar conexão in-memory
con = duckdb.connect()
# Consulta simples
resultado = con.sql("SELECT 42 AS resposta")
print(resultado.fetchone())
# (42,)
O DuckDB também funciona sem criar conexão explícita — você pode usar o módulo diretamente:
import duckdb
# Sem conexão explícita
df = duckdb.sql("SELECT * FROM range(10) AS t(numero)").df()
print(df)
O método .df() converte o resultado diretamente para um DataFrame do Pandas, e .pl() converte para Polars.
SQL Direto em Arquivos CSV e Parquet
Uma das features mais poderosas do DuckDB é consultar arquivos sem carregá-los em memória primeiro:
import duckdb
# Consultar CSV diretamente
resultado = duckdb.sql("""
SELECT
cidade,
COUNT(*) as total,
AVG(salario) as salario_medio
FROM 'dados_funcionarios.csv'
GROUP BY cidade
ORDER BY salario_medio DESC
LIMIT 10
""")
print(resultado.df())
Com arquivos Parquet, a performance é ainda melhor porque o DuckDB aproveita o formato colunar para ler apenas as colunas necessárias:
import duckdb
# Ler múltiplos arquivos Parquet com glob
resultado = duckdb.sql("""
SELECT
ano,
SUM(receita) as receita_total,
COUNT(DISTINCT cliente_id) as clientes_unicos
FROM 'dados/vendas_*.parquet'
WHERE ano >= 2024
GROUP BY ano
ORDER BY ano
""")
print(resultado.df())
Integração com Pandas e Polars
O DuckDB se integra perfeitamente com o ecossistema Python de dados. Você pode rodar SQL diretamente em DataFrames que já existem na memória:
import pandas as pd
import duckdb
# Criar DataFrame do Pandas
vendas = pd.DataFrame({
"produto": ["Notebook", "Mouse", "Teclado", "Monitor", "Notebook"],
"valor": [4500, 120, 280, 1800, 5200],
"quantidade": [10, 150, 80, 25, 8],
"regiao": ["Sul", "Sudeste", "Sul", "Nordeste", "Sudeste"]
})
# SQL direto no DataFrame — sem cópia de dados!
resultado = duckdb.sql("""
SELECT
regiao,
SUM(valor * quantidade) as faturamento,
COUNT(*) as num_vendas
FROM vendas
GROUP BY regiao
ORDER BY faturamento DESC
""")
print(resultado.df())
O DuckDB referencia o DataFrame pelo nome da variável Python — não precisa importar nem registrar nada. Ele também funciona com Polars:
import polars as pl
import duckdb
# DataFrame Polars
df_polars = pl.DataFrame({
"nome": ["Ana", "Bruno", "Carla", "Diego"],
"idade": [28, 35, 42, 31],
"linguagem": ["Python", "Go", "Rust", "Python"]
})
# SQL direto no Polars DataFrame
resultado = duckdb.sql("""
SELECT linguagem, AVG(idade) as idade_media
FROM df_polars
GROUP BY linguagem
""")
# Converter de volta para Polars
print(resultado.pl())
Window Functions e Consultas Avançadas
O DuckDB suporta SQL completo, incluindo window functions que são difíceis de replicar com Pandas puro:
import duckdb
# Criar tabela de exemplo
con = duckdb.connect()
con.sql("""
CREATE TABLE vendas AS
SELECT * FROM (VALUES
('2024-01', 'Eletrônicos', 45000),
('2024-02', 'Eletrônicos', 52000),
('2024-03', 'Eletrônicos', 48000),
('2024-01', 'Roupas', 32000),
('2024-02', 'Roupas', 28000),
('2024-03', 'Roupas', 35000)
) AS t(mes, categoria, receita)
""")
# Window functions: ranking e média móvel
resultado = con.sql("""
SELECT
mes,
categoria,
receita,
RANK() OVER (PARTITION BY mes ORDER BY receita DESC) as ranking,
AVG(receita) OVER (
PARTITION BY categoria
ORDER BY mes
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
) as media_movel
FROM vendas
ORDER BY mes, ranking
""")
print(resultado.df())
Isso seria muito mais verboso e lento usando .groupby() e .rolling() do Pandas.
DuckDB vs Pandas: Quando Usar Cada Um
A pergunta que todo mundo faz: quando trocar Pandas por DuckDB?
| Cenário | Pandas | DuckDB |
|---|---|---|
| Datasets pequenos (<100MB) | Ótimo | Funciona, mas desnecessário |
| Datasets grandes (1GB+) | Lento, consome muita RAM | Excelente, processamento colunar |
| Agregações complexas | Verboso com groupby | SQL natural e rápido |
| Window functions | Difícil e lento | SQL nativo, muito rápido |
| Manipulação célula a célula | Ideal com .apply() | Não é o forte |
| Leitura de Parquet | Carrega tudo em memória | Lê apenas colunas necessárias |
| Joins em tabelas grandes | Lento com merge() | Otimizado com hash joins |
Benchmark prático
Para dar uma ideia concreta, aqui vai um comparativo com 10 milhões de linhas:
import pandas as pd
import duckdb
import time
# Gerar dataset grande
n = 10_000_000
df = pd.DataFrame({
"categoria": [f"cat_{i % 100}" for i in range(n)],
"valor": range(n),
"regiao": [f"reg_{i % 10}" for i in range(n)]
})
# Pandas
inicio = time.time()
resultado_pandas = df.groupby(["categoria", "regiao"])["valor"].agg(["sum", "mean", "count"])
tempo_pandas = time.time() - inicio
# DuckDB
inicio = time.time()
resultado_duckdb = duckdb.sql("""
SELECT categoria, regiao, SUM(valor), AVG(valor), COUNT(*)
FROM df
GROUP BY categoria, regiao
""").df()
tempo_duckdb = time.time() - inicio
print(f"Pandas: {tempo_pandas:.2f}s")
print(f"DuckDB: {tempo_duckdb:.2f}s")
# Resultado típico: Pandas ~3.5s, DuckDB ~0.4s
Em agregações com datasets grandes, o DuckDB costuma ser 5 a 10 vezes mais rápido que o Pandas.
Persistência e Banco de Dados em Disco
Embora o modo in-memory seja o mais comum, o DuckDB também persiste dados em disco:
import duckdb
# Criar banco persistente
con = duckdb.connect("meu_banco.duckdb")
# Criar e popular tabela
con.sql("""
CREATE TABLE IF NOT EXISTS clientes (
id INTEGER PRIMARY KEY,
nome VARCHAR,
email VARCHAR,
criado_em TIMESTAMP DEFAULT current_timestamp
)
""")
con.sql("""
INSERT INTO clientes (id, nome, email) VALUES
(1, 'Ana Silva', 'ana@email.com'),
(2, 'Bruno Costa', 'bruno@email.com')
""")
# Os dados persistem entre sessões
con.close()
# Reabrir depois
con = duckdb.connect("meu_banco.duckdb")
print(con.sql("SELECT * FROM clientes").df())
con.close()
O arquivo .duckdb é portátil — você pode compartilhá-lo com colegas ou incluir em pipelines de dados.
DuckDB em Projetos Reais
ETL simples com DuckDB
import duckdb
con = duckdb.connect()
# Extrair de CSV, transformar com SQL, carregar em Parquet
con.sql("""
COPY (
SELECT
UPPER(nome) as nome,
CAST(salario AS DECIMAL(10,2)) as salario,
CASE
WHEN salario > 10000 THEN 'senior'
WHEN salario > 5000 THEN 'pleno'
ELSE 'junior'
END as nivel
FROM 'funcionarios_raw.csv'
WHERE salario IS NOT NULL
) TO 'funcionarios_limpo.parquet' (FORMAT PARQUET)
""")
Análise exploratória rápida
import duckdb
# Resumo estatístico instantâneo de qualquer arquivo
resumo = duckdb.sql("""
SUMMARIZE SELECT * FROM 'dataset.parquet'
""")
print(resumo.df())
O comando SUMMARIZE gera estatísticas descritivas (min, max, média, desvio padrão, nulos) automaticamente — parecido com df.describe() do Pandas, mas funciona direto no arquivo.
Quando NÃO Usar DuckDB
O DuckDB é fantástico para analytics, mas não é solução para tudo:
- Aplicações web com múltiplos usuários — use PostgreSQL ou MongoDB
- Cache e filas — use Redis
- Dados simples e leves — SQLite continua sendo suficiente
- Streaming de dados em tempo real — use ferramentas como Kafka ou MQTT
O DuckDB é ideal para análise de dados local, ETL, exploração de datasets e qualquer cenário onde você precisa de SQL rápido sem infraestrutura.
Conclusão
O DuckDB preenche uma lacuna importante no ecossistema Python de dados: análise rápida sem complexidade. Ele combina a simplicidade do SQLite com a potência de um banco analítico moderno, e a integração nativa com Pandas e Polars torna a adoção praticamente sem atrito.
Se você trabalha com ciência de dados ou precisa processar datasets que não cabem confortavelmente no Pandas, o DuckDB merece um lugar no seu toolkit. A curva de aprendizado é mínima — se você sabe SQL, já sabe usar DuckDB.
Se performance é prioridade nos seus projetos, vale conhecer também o Rust, a linguagem por trás de ferramentas como Polars e Ruff que estão revolucionando o ecossistema Python.
Para quem trabalha com análise de dados e quer explorar uma linguagem compilada com ótimo suporte a concorrência, confira o Go — muito usado em pipelines de dados e ferramentas de infraestrutura.
Equipe python.dev.br
Contribuidor do Python Brasil — Aprenda Python em Português