Balança comercial em uma query DuckDB¶
Tempo estimado: 10 minutos (incluindo o primeiro download). Pacotes:
comex-fetcher,duckdb.
Dados de comércio exterior do Brasil são grandes. Cada arquivo anual do Siscomex em granularidade NCM-8 passa de 1 GB. A receita aqui mostra como combinar dois superpoderes: o coletor resiliente que lida com o servidor governamental, e o DuckDB lendo Parquet direto do disco para consultar bilhões de linhas em segundos.
O que você vai ver¶
A balança comercial mensal do Brasil — exportações menos importações — calculada sobre o conjunto completo de transações, sem carregar nada em memória.
Setup¶
uv add "comex-fetcher @ git+https://github.com/Quantilica/comex-fetcher.git" duckdb
A receita¶
1. Baixar e converter para Parquet¶
# Importações e exportações dos últimos 5 anos
comex-fetcher fetch imp exp --start 2020 --end 2024 --data-dir ./dados
comex-fetcher convert ./dados --output ./parquet --format parquet
Você fica com algo como:
parquet/
├── imp_2020.parquet
├── imp_2021.parquet
├── ...
├── exp_2024.parquet
└── codigos/
├── pais.parquet
├── ncm.parquet
└── ...
2. Consultar com DuckDB¶
import duckdb
con = duckdb.connect()
balanca = con.execute("""
WITH exportacoes AS (
SELECT
CAST(strftime(CAST(printf('%04d-%02d-01', co_ano, co_mes) AS DATE), '%Y-%m') AS DATE) AS mes,
SUM(vl_fob) AS exportacao
FROM read_parquet('parquet/exp_*.parquet')
GROUP BY co_ano, co_mes
),
importacoes AS (
SELECT
CAST(strftime(CAST(printf('%04d-%02d-01', co_ano, co_mes) AS DATE), '%Y-%m') AS DATE) AS mes,
SUM(vl_fob) AS importacao
FROM read_parquet('parquet/imp_*.parquet')
GROUP BY co_ano, co_mes
)
SELECT
e.mes,
e.exportacao,
i.importacao,
e.exportacao - i.importacao AS saldo
FROM exportacoes e
JOIN importacoes i USING (mes)
ORDER BY e.mes
""").pl()
print(balanca.tail(12))
O que está acontecendo¶
- Sem carregar em memória. O DuckDB faz predicate pushdown no Parquet — lê só as colunas e linhas necessárias. Mesmo com 20 GB no disco, a query usa menos de 1 GB de RAM.
- Glob no
read_parquet.'parquet/exp_*.parquet'agrega todos os anos automaticamente. Tipos são unificados pelo DuckDB. .pl()no fim. Materializa o resultado final em Polars para uso posterior — só o que coube noSELECTfinal fica em memória.
Pegadinhas¶
co_anoeco_messão inteiros, não datas. O Siscomex publica em colunas separadas; oprintf+CAST AS DATEreconstrói.vl_fobestá em USD. Para balança em reais, junte com a cotação cambial (BCB SGS 1 outesouro-direto-fetcher) — mas para evolução, USD é o padrão internacional.- Mês corrente é parcial. O Siscomex publica mês fechado por volta do dia 15 do mês seguinte. Filtre
co_mespara evitar séries com o último ponto incompleto. - NCM mudou. O sistema NCM 8 cobre 1997+. Pré-1997 (NBM) tem schema diferente — não tente unir os dois Parquets.
Variações¶
- Top 10 produtos exportados —
GROUP BY co_ncm, join comcodigos/ncm.parquetpara nomes. - Concentração geográfica —
GROUP BY co_pais, join comcodigos/pais.parquet. - Análise por estado —
GROUP BY sg_uf_ncmem vez de mês. - Saldo bilateral com a China — filtre
co_pais = '160'(China) e plote.