DuckDB com Python permite executar SQL diretamente sobre arquivos CSV, Parquet e DataFrames, sem instalar nem administrar um servidor. A resposta direta é: instale o pacote duckdb, abra uma conexão e consulte a fonte com read_csv, read_parquet ou pelo nome de um DataFrame disponível no processo. Isso é especialmente útil em análise local, notebooks, pipelines e scripts que precisam combinar a expressividade do SQL com o ecossistema Python.
O DuckDB é um banco analítico embutido e colunar. “Embutido” significa que ele roda dentro do processo Python; “analítico” indica que foi projetado para varreduras, agregações e junções, não para milhares de pequenas transações concorrentes. Se você está começando na área, consulte também nosso guia de Python para Data Science e a introdução ao pandas para análise de dados.
Instalação e primeira consulta
Crie um ambiente isolado e fixe as dependências do projeto. O artigo sobre ambientes virtuais com venv mostra por que isso evita conflitos. Depois, instale os pacotes necessários:
python -m pip install duckdb pandas pyarrow
Uma conexão sem caminho vive em memória. Use-a com um gerenciador de contexto para liberar recursos mesmo quando ocorrer uma exceção:
import duckdb
with duckdb.connect() as con:
total = con.execute("""
SELECT region, sum(valor) AS receita
FROM read_csv('dados/vendas.csv', header = true)
GROUP BY region
ORDER BY receita DESC
""").fetchall()
print(total)
fetchall() devolve tuplas Python. Para continuar a exploração de forma tabular, use .df() para pandas ou .arrow() para Arrow. Não materialize milhões de linhas sem necessidade: agregue, filtre e selecione colunas no SQL antes de buscar o resultado.
Consultar CSV com tipos previsíveis
read_csv detecta cabeçalho, delimitador e tipos, mas inferência não deve substituir um contrato de dados. Datas ambíguas, identificadores com zeros à esquerda e colunas mistas podem ser interpretados incorretamente. Em rotinas estáveis, informe opções e tipos relevantes:
sql = """
SELECT
pedido_id,
CAST(data_pedido AS DATE) AS data_pedido,
valor
FROM read_csv(
?,
header = true,
delim = ';',
columns = {
'pedido_id': 'VARCHAR',
'data_pedido': 'VARCHAR',
'valor': 'DECIMAL(12,2)'
}
)
WHERE valor >= ?
"""
with duckdb.connect() as con:
pedidos = con.execute(sql, ['dados/pedidos.csv', 100]).df()
Os marcadores ? separam valores do texto SQL e evitam concatenação insegura. Parâmetros servem para caminhos e valores escalares, mas nomes de tabela ou coluna exigem composição controlada por uma lista permitida. Para detalhes sobre formatos tabulares no Python, veja manipulação de CSV e outros arquivos.
Por que Parquet combina com DuckDB
Parquet armazena dados por coluna e inclui metadados estatísticos. Assim, uma consulta que pede três colunas não precisa decodificar todas as demais, e filtros podem eliminar grupos de linhas. A documentação oficial explica a leitura e escrita de Parquet no DuckDB.
with duckdb.connect() as con:
resumo = con.execute("""
SELECT date_trunc('month', data) AS mes,
categoria,
avg(valor) AS ticket_medio
FROM read_parquet('lake/vendas/**/*.parquet', hive_partitioning = true)
WHERE data >= DATE '2026-01-01'
GROUP BY ALL
ORDER BY mes, categoria
""").df()
O glob reúne vários arquivos com o mesmo esquema. hive_partitioning interpreta diretórios como ano=2026/mes=07 como colunas. Antes de confiar no conjunto, inspecione esquemas e trate evolução de colunas deliberadamente; arquivos incompatíveis podem exigir union_by_name = true, mas essa opção não corrige significados conflitantes.
SQL sobre DataFrames
O DuckDB encontra um DataFrame pandas pelo nome no escopo Python. O registro explícito, porém, deixa dependências claras e funciona melhor em funções:
import pandas as pd
import duckdb
clientes = pd.DataFrame({
'cliente_id': [1, 2, 3],
'segmento': ['B2B', 'B2C', 'B2B'],
})
with duckdb.connect() as con:
con.register('clientes_df', clientes)
ativos = con.execute("""
SELECT c.segmento, count(*) AS pedidos
FROM read_parquet('dados/pedidos.parquet') p
JOIN clientes_df c USING (cliente_id)
WHERE p.status = 'pago'
GROUP BY c.segmento
""").df()
con.unregister('clientes_df')
Esse padrão cruza uma dimensão pequena em memória com fatos no Parquet, sem exportar o DataFrame. Não altere o objeto em outra thread durante a consulta. Para operações vetoriais que permanecem em Python, o guia de NumPy complementa o fluxo.
Persistência, views e exportação
Troque duckdb.connect() por duckdb.connect('analytics.duckdb') para manter tabelas entre execuções. Uma view sobre arquivos guarda a consulta, não uma cópia dos dados. Uma tabela criada com CREATE TABLE AS materializa o resultado no banco.
with duckdb.connect('analytics.duckdb') as con:
con.execute("""
CREATE OR REPLACE VIEW vendas AS
SELECT * FROM read_parquet('dados/vendas/*.parquet')
""")
con.execute("""
COPY (
SELECT categoria, sum(valor) AS total
FROM vendas GROUP BY categoria
) TO 'saida/resumo.parquet' (FORMAT PARQUET)
""")
Use transações quando várias alterações precisarem ser atômicas. Evite compartilhar a mesma conexão de modo desordenado entre threads e processos. A referência oficial da API Python do DuckDB detalha conexões, resultados e tipos; a página de importação de CSV lista as opções do leitor.
Erros comuns
- Usar
SELECT *sempre: aumenta leitura, transferência e acoplamento ao esquema. Nomeie apenas as colunas necessárias. - Confiar cegamente na inferência do CSV: valide tipos, nulos, delimitador, codificação e formato de datas.
- Interpolar entradas em SQL: use parâmetros para valores e listas permitidas para identificadores.
- Buscar tudo para pandas cedo demais: faça filtros, joins e agregações no DuckDB antes de materializar.
- Tratar DuckDB como servidor OLTP: ele não substitui um banco transacional multiusuário para a aplicação.
- Ignorar caminhos relativos: resolva caminhos a partir de uma base conhecida para que scripts funcionem fora do notebook.
Checklist para uma análise confiável
- Crie ambiente virtual e registre versões das dependências.
- Defina esquema, formato de datas e política de valores nulos.
- Selecione colunas e aplique filtros antes de materializar resultados.
- Parametrize valores externos e valide identificadores dinâmicos.
- Confira contagens, chaves de junção e duplicidades com consultas de controle.
- Escolha conexão em memória para trabalho descartável ou arquivo para persistência.
- Exporte resultados em Parquet quando tipos e eficiência de leitura importarem.
- Teste o script com arquivos vazios, esquemas alterados e dados inválidos.
DuckDB é uma escolha direta quando os dados estão em arquivos ou objetos Python e o trabalho é analítico. Comece com uma consulta pequena, torne tipos e caminhos explícitos e deixe o mecanismo reduzir os dados antes de entregá-los ao pandas. Esse desenho mantém o código simples, reproduzível e mais fácil de revisar.