Shopping cart

Subtotal $0.00

View cartCheckout

Building better devs

TnewsTnews
Banco de Dados

DuckDB 2.0: 10.000 Commits e o Banco que Virou Servidor

Email : 4

Eu lembro de quando conheci o DuckDB. Era 2022, eu estava frustrado com Pandas travando num DataFrame de 200 milhões de linhas, e um colega sugeriu: “tenta DuckDB, roda tudo em SQL direto no arquivo Parquet”. Fiz um teste e a query que demorava 3 minutos rodou em 4 segundos. Desde então, o DuckDB virou peça obrigatória no meu toolkit de dados.

Mas o DuckDB sempre teve uma limitação clara: era um banco embedded. Ótimo para análise local, terrível se dois processos precisassem acessar o mesmo banco ao mesmo tempo. Isso mudou. O DuckDB 2.0, codinome “Cyanoptera”, traz mais de 10.000 commits desde a versão 1.5 (março de 2026) e transforma o projeto num banco de dados completo, com modo servidor, triggers, I/O assíncrono e um parser SQL inteiramente novo.

Vamos ao que interessa.

DuckDB como servidor: o protocolo Quack

A mudança mais significativa do 2.0 é a extensão Quack, que permite rodar o DuckDB como servidor. Não é gambiarra de terceiro, é extensão oficial do time core.

O Quack funciona sobre HTTP com serialização Protobuf. Você instala com INSTALL quack, inicia o modo servidor, e qualquer outro processo DuckDB na rede pode se conectar como cliente. O protocolo usa TLS para conexões remotas e a porta padrão é 9494.


-- No servidor
INSTALL quack;
LOAD quack;
CALL quack_start_server('0.0.0.0', 9494);

-- No cliente
INSTALL quack;
LOAD quack;
CONNECT TO 'quack://192.168.1.100:9494';
SELECT * FROM remote_db.vendas WHERE ano = 2026;

O mais impressionante é o que acontece por baixo. O otimizador de remote pushdown identifica que a query pode ser executada no servidor e envia o SQL diretamente, evitando tráfego de dados desnecessário. Isso funciona inclusive com PostgreSQL e MySQL como backends: o DuckDB roteia a query pro banco remoto, executa lá, e traz só o resultado.

A arquitetura mantém MVCC completo e isolamento transacional em deployments multi-conexão. Na prática, isso significa que o DuckDB deixou de ser “aquele banco local legal” para competir de igual com soluções como ClickHouse e Trino em cenários analíticos distribuídos.

VARIANT: JSON turbinado

Se você já trabalhou com dados semi-estruturados, sabe a dor. JSON no banco de dados é lento, ocupa espaço demais e consultas em campos aninhados viram pesadelo de performance.

O tipo VARIANT do DuckDB 2.0 resolve isso de um jeito que eu nunca vi em outro banco. O time chama de “JSON on steroids”, e com razão. O VARIANT detecta automaticamente a estrutura dos dados, aplica compressão inteligente, e faz o que eles chamam de “shredded execution”: em vez de parsear JSON em runtime, os campos são decompostos no storage e acessados diretamente durante o scan.


-- Inserir dados semi-estruturados
CREATE TABLE eventos (id INTEGER, payload VARIANT);
INSERT INTO eventos VALUES
  (1, '{"tipo": "click", "pagina": "/home", "meta": {"browser": "Chrome"}}'),
  (2, '{"tipo": "compra", "valor": 149.90, "items": ["camiseta", "boné"]}');

-- Consultar com extraction pushdown (não parseia o JSON inteiro)
SELECT variant_extract(payload, '$.tipo') AS tipo,
       variant_extract(payload, '$.meta.browser') AS browser
FROM eventos
WHERE variant_extract(payload, '$.tipo') = 'click';

O suporte inclui leitura e escrita de Parquet com dados VARIANT “shredded”. Na prática, seus pipelines de dados podem manter a flexibilidade do JSON com a performance de colunas tipadas.

Triggers: finalmente

Sim, o DuckDB agora tem triggers. E não é uma implementação meia-boca.

Suporta BEFORE e AFTER, tanto FOR EACH ROW quanto FOR EACH STATEMENT. Tem tabelas de transição via REFERENCING OLD/NEW TABLE, múltiplos triggers por evento, e cláusula RETURNING.


CREATE TABLE audit_log (
  tabela TEXT,
  operacao TEXT,
  dados_antigos VARIANT,
  dados_novos VARIANT,
  timestamp TIMESTAMPTZ DEFAULT now()
);

CREATE TRIGGER audit_vendas
AFTER INSERT OR UPDATE OR DELETE ON vendas
FOR EACH ROW
EXECUTE FUNCTION registrar_auditoria();

Pra quem usa DuckDB em pipelines ETL, isso abre possibilidades que antes exigiam orquestração externa. Validação de dados no insert, log de auditoria automático, materialização incremental de agregações. Tudo nativo.

I/O assíncrono: a mudança silenciosa que muda tudo

Se você roda DuckDB contra dados no S3, essa feature sozinha justifica o upgrade.

Até a versão 1.5, toda leitura era síncrona: a thread de execução parava, esperava o I/O completar, e só então processava os dados. Em setups EC2/S3 (que é basicamente o cenário de toda empresa que usa lakehouse), a CPU ficava ociosa esperando a rede.

O DuckDB 2.0 desacopla I/O da execução de queries. Enquanto uma thread espera dados do storage, outras continuam processando. A implementação começa com Parquet (leitura e escrita assíncrona), e CSV e o formato nativo DuckDB vêm na sequência.

Além disso, o 2.0 introduz dois novos modos de acesso: MMAP (memory-mapped files) e DIRECT_IO (bypass do cache do OS). Dependendo do cenário, a diferença é brutal.

40x mais rápido em CTEs recursivas

Esse número merece destaque próprio. CTEs recursivas são fundamentais para grafos, hierarquias, e qualquer tipo de travessia de dados conectados. No DuckDB 1.5.4, uma query de alcançabilidade em um grafo de 1 milhão de arestas demorava 4.90 segundos. No preview do 2.0, a mesma query roda em 0.12 segundo.

A melhoria vem de uma nova keyword USING KEY que permite agregação durante a recursão, evitando explosão de estado intermediário:


-- Caminho mais curto em grafo ponderado
WITH RECURSIVE shortest_path AS (
  SELECT destino, custo
  FROM arestas
  WHERE origem = 'A'
  UNION ALL
  SELECT e.destino, sp.custo + e.custo
  FROM shortest_path sp
  JOIN arestas e ON sp.destino = e.origem
  USING KEY (destino) -- agrega pelo destino, mantém menor custo
)
SELECT * FROM shortest_path;

Se você faz análise de grafos e estava usando Neo4j só por performance em travessias, vale testar de novo.

O novo parser SQL

O DuckDB 2.0 traz um parser SQL completamente novo, substituindo o parser derivado do PostgreSQL que era usado desde o início do projeto. O novo parser é baseado em PEG (Parsing Expression Grammar) e foi escrito do zero pelo time.

Por que isso importa? Três razões.

Primeiro, mensagens de erro melhores. O novo parser aponta exatamente onde está o erro na query, com localização precisa no código fonte. Quem já debugou um “syntax error at or near …” genérico do PostgreSQL sabe o quanto isso dói.

Segundo, extensibilidade em runtime. Extensões podem registrar novas gramáticas SQL sem recompilar o DuckDB. Isso abre a porta para dialetos customizados e DSLs (Domain Specific Languages) dentro do SQL.

Terceiro, modo de compatibilidade de dialeto. Com SET dialect_compatibility_mode = 'spark', o DuckDB aceita sintaxe Spark SQL. Migrar queries de um Databricks para DuckDB local ficou trivial.


-- Ativar compatibilidade com Spark SQL
SET dialect_compatibility_mode = 'spark';

-- Query com sintaxe Spark funciona direto
SELECT date_format(created_at, 'yyyy-MM-dd') AS dia,
       collect_list(produto) AS produtos
FROM vendas
GROUP BY 1;

SQL que nenhum outro banco tem

O DuckDB 2.0 adiciona funcionalidades SQL que vão te fazer questionar por que o PostgreSQL nunca implementou isso.

NEAREST joins permitem busca de similaridade top-k diretamente no SQL:


SELECT p.nome, v.embedding
FROM produtos p
APPROX NEAREST BY SIMILARITY(p.embedding, v.embedding, 'cosine')
JOIN vetores v
LIMIT 10;

DML em CTEs permite encadear operações de escrita como etapas de um pipeline:


WITH movidos AS (
  DELETE FROM staging
  WHERE processado = true
  RETURNING *
),
inseridos AS (
  INSERT INTO historico
  SELECT * FROM movidos
  RETURNING id
)
SELECT count(*) FROM inseridos;

Schemas aninhados (CREATE SCHEMA finance.reports), variáveis com sintaxe $x em vez de getvariable(), e mutação de JSON nativa (json_set, json_insert, json_replace, json_remove) completam o pacote.

Formato de storage v2.0

O storage interno ganhou uma reescrita significativa. As mudanças mais relevantes:

Feature Antes (v1.x) Agora (v2.0)
Carregamento de metadados de coluna Eager (tudo de uma vez) Lazy (sob demanda)
Compressão de strings FSST DICT_FSST (padrão)
Armazenamento de deletes Bitmap completo Formato compacto
Validação de corrupção Básica Forte na leitura
Checkpoint com ART index Rebuild completo Remapeamento incremental

A compressão DICT_FSST combina dicionário com FSST (Fast Static Symbol Table) e reduz significativamente o tamanho de colunas de string repetitivas, que é o cenário mais comum em dados analíticos (categorias, status, nomes de cidades).

O carregamento lazy de metadados significa que abrir um arquivo DuckDB com centenas de colunas não carrega tudo na memória. Só as colunas que a query precisa têm seus metadados lidos. Em data lakes com tabelas wide (100+ colunas), isso faz diferença real no tempo de abertura.

ICU foi embora (e ninguém sentiu falta)

A biblioteca ICU (International Components for Unicode) era uma dependência pesada do DuckDB para lidar com timezones, calendários e collations. No 2.0, o time reimplementou tudo nativamente na extensão icu, usando dados direto do IANA comprimidos para ~45 KB.

Os números falam por si:

Operação v1.x (ICU) v2.0 (nativo) Ganho
——-
Conversão de timezone (25M linhas) Baseline 2.2x mais rápido +120%
Filtro com collation alemã (5M linhas) Baseline 2.6x mais rápido +160%

Menos dependência, binário menor, performance melhor. Triângulo raro onde você ganha nos três eixos.

API C estável para extensões

Esse ponto é mais relevante para quem desenvolve extensões, mas o impacto é enorme para o ecossistema. Até agora, extensões precisavam ser recompiladas para cada versão do DuckDB. A nova API C estável usa versionamento via YAML e permite que uma extensão compilada uma vez funcione em múltiplas versões do DuckDB.

Além disso, agora é possível criar repositórios de extensões customizados com assinatura RSA e key pinning SHA-256. Empresas podem distribuir extensões proprietárias com segurança:


-- Adicionar repositório corporativo
CREATE EXTENSION REPOSITORY 'https://extensions.empresa.com'
WITH PUBLIC KEY 'MIIBIjANBgkq...';

-- Instalar extensão privada
INSTALL minha_extensao FROM 'empresa';

Pruning de row-groups expandido

O DuckDB já fazia min-max pruning (pular blocos de dados que não satisfazem o filtro), mas o 2.0 expande isso para structs, lists, decimals e UUIDs. Suporte a Bloom filters do Parquet também foi adicionado, junto com pushdown de predicados em chamadas de função e filtros IN.

Na prática, queries em data lakes grandes (terabytes de Parquet no S3) vão ler significativamente menos dados, o que significa menos custo de transferência e execução mais rápida.

Agregações que transbordam para disco

Até a 1.5, se uma agregação não cabia na memória, a query falhava. No 2.0, agregações fazem spillover para disco automaticamente. Isso é fundamental para cenários serverless onde a memória é limitada, e para queries exploratórias onde você não sabe de antemão se o GROUP BY vai gerar 1.000 ou 100 milhões de grupos.

Materialização 2.2x mais rápida no Windows

Um detalhe que quase passa despercebido no changelog: a CLI do Windows ficou 2.2x mais rápida na materialização de resultados multi-threaded. Se você usa DuckDB no Windows (e muita gente usa, especialmente analistas de dados), queries que antes travavam a tela por segundos agora fluem. O time otimizou a forma como threads convergem para exibir o resultado final no terminal, e o ganho é perceptível até em queries pequenas.

Combinado com o partition-aware query planning (que aproveita o particionamento existente em formatos lakehouse como Delta Lake e Iceberg), o DuckDB 2.0 fica significativamente mais inteligente sobre como ler e processar dados particionados. Em vez de escanear todas as partições e filtrar depois, o planner elimina partições inteiras antes de iniciar qualquer I/O.

O que o 2.0 quebra

Toda major version traz breaking changes, e o DuckDB 2.0 não é exceção. O novo formato de storage padrão significa que arquivos criados com v2.0 não abrem em versões anteriores (o contrário funciona: o 2.0 lê arquivos 1.x). A transição da sintaxe de lambdas foi completada, então code antigo que usava a sintaxe legada precisa ser atualizado.

Os detalhes completos das breaking changes serão publicados no release final (previsto para o outono de 2026), mas preview builds já estão disponíveis para teste.

Governança e o futuro

A DuckDB Foundation está adicionando um conselho consultivo de stakeholders no outono de 2026. O roadmap agora cobre três projetos: DuckDB (o banco), DuckLake (lakehouse format nativo), e Quack (protocolo de rede). A mensagem é clara: o DuckDB quer ser a stack completa de dados analíticos, do storage local ao cluster distribuído.

Pra quem acompanha o projeto desde os tempos de “SQLite para analytics”, a evolução é impressionante. O DuckDB 2.0 não é mais um banco embedded que virou servidor. É um banco de dados analítico completo que, por acaso, também roda embedded.

Se você ainda está usando Pandas para processar DataFrames grandes, ou rodando Spark local “porque precisa de SQL”, o DuckDB 2.0 é o empurrão que faltava pra repensar sua stack. Baixe o preview, teste com seus dados reais, e me conta nos comentários se os 40x de speedup se confirmam no seu cenário.


Fonte de inspiração: A Preview of DuckDB v2.0 (DuckDB Blog)

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts