O que lakehouse faz?
Suporte de decisão de referência para armazenamento em formato de tabela aberta e código Spark. Versões e datas estão em references/landscape-2026-11.md; verifique-as antes de qualquer afirmação específica de versão. Para especificidades de Databricks, Snowflake ou serviços AWS, use a skill de-vendors e as skills oficiais de fornecedor que ela indica.
1. Um lakehouse é justificado?
Comece pela opção mais barata que se encaixa e suba apenas quando um gatilho listado for real e medido.
- Postgres (ou DuckDB em um conjunto de arquivos) quando os dados estão abaixo de aproximadamente 1 TB, um único mecanismo os lê e poucos usuários analíticos concorrentes existem. Motivo: sem catálogo, sem compactação, sem cluster para executar.
- Warehouse em nuvem quando muitos usuários SQL precisam de concorrência elástica e ninguém precisa de um segundo mecanismo nos mesmos bytes. Motivo: armazenamento gerenciado, manutenção e governança estão incluídos no preço.
- Lakehouse quando pelo menos uma condição se aplica: dezenas de TB ou mais; vários mecanismos (Spark, Trino, DuckDB, Python) precisam ler uma única cópia; cargas de trabalho baseadas em ML ou arquivos compartilham tabelas com SQL; o custo de armazenamento em object storage supera claramente o armazenamento de warehouse no seu volume; formato aberto é um requisito rigoroso (saída, auditoria, neutralidade de fornecedor).
- Não escolha um lakehouse para uma "escala futura" que não tenha números associados. Pergunte por contagens de linhas, crescimento diário, leitores concorrentes e mecanismos antes de recomendar.
- Dados pequenos e médios que ainda desejam formato aberto: DuckLake ou Parquet simples mais DuckDB supera a execução do Spark.
2. Layout do Parquet
- Mire de 128 MB a 1 GB por arquivo; busque de 256 MB a 512 MB quando estiver em dúvida. Muitos arquivos abaixo de 32 MB significam que os custos de listagem e abertura dominam a consulta.
- Grupos de linhas de aproximadamente 128 MB descomprimidos (1M+ linhas) por arquivo; grupos menores enfraquecem a poda min/max e a compressão.
- Particione apenas por colunas de baixa cardinalidade que as consultas filtram (data ou mês, região). Uma boa partição contém pelo menos um arquivo do tamanho alvo completo por lote de escritor; se as partições tiverem em média menos de 1 GB, use um grão mais grosso ou clustering.
- Nunca particione por um id de alta cardinalidade. Use clustering (Delta liquid clustering, Iceberg sort order / Z-order) para essas colunas.
- Ordene ou agrupe dentro dos arquivos pela coluna mais filtrada para que as estatísticas min/max eliminem grupos de linhas.
- Escritas de streaming ou micro-batches frequentes criam arquivos pequenos; agende compactação, não confie que os escritores dimensionem os arquivos.
3. Escolhendo um formato de tabela
Decida pelo mecanismo e catálogo que você já possui, não por listas de funcionalidades.
- Delta Lake: escolha quando Databricks ou Spark for o mecanismo principal, ou Unity Catalog já for a camada de governança. Melhor integração com Spark; outros mecanismos leem, mas o suporte a escrita varia.
- Apache Iceberg: escolha quando vários mecanismos precisam escrever, ou você quiser catálogos neutros de fornecedor (REST). v3 adiciona vetores de exclusão, linhagem de linhas e um tipo variante; confirme se cada mecanismo e catálogo no caminho suporta os recursos v3 que você usa antes de atualizar uma tabela, porque um leitor antigo falha em uma versão de formato mais nova.
- DuckLake: escolha para dados pequenos e médios, uma única equipe, e um banco de dados SQL que você já opera como catálogo (metadados vivem em tabelas simples). Barato de executar, ecossistema jovem; não escolha quando Spark, Trino ou Snowflake precisam escrever as mesmas tabelas.
- Camadas de interoperabilidade (Delta UniForm, metadados Iceberg para tabelas Delta) são caminhos de leitura. Escolha um formato como escritor de registro por tabela.
- Mudar de formato depois significa uma reescrita ou conversão de metadados; escolha o escritor de registro deliberadamente.
4. Catálogos
- O catálogo é o coordenador de commits e o ponto de controle de acesso; escolha-o antes que os detalhes do formato importem.
- Unity Catalog: o padrão centrado no Databricks; governança para Delta e Iceberg.
- AWS Glue e S3 Tables: escolha quando a pilha é nativa da AWS; S3 Tables gerencia compactação para você, mas o prende à AWS.
- Catálogo Iceberg REST (por exemplo Polaris): escolha para neutralidade multi-mecanismo e multi-nuvem.
- DuckLake: o catálogo é um banco de dados SQL; use Postgres para uso multiusuário, SQLite ou DuckDB apenas para um escritor.
- Nunca permita que dois catálogos registrem o mesmo caminho de tabela; commits para um corromperão a visão do outro.
5. Manutenção (agende-a, ou a tabela se degrada)
- Compacte arquivos pequenos: Delta
OPTIMIZE, Icebergrewrite_data_files, DuckLake mesclar-arquivos-adjacentes. Execute após ingestão pesada, não por escrita. - Remova dados antigos: Delta
VACUUM, Icebergexpire_snapshotsmais remoção de arquivos órfãos, DuckLake expirar snapshots e depois limpar. A retenção deve exceder a janela do leitor mais longo ou de time-travel, porque excluir arquivos sob um leitor em execução o quebra. - Clustering ou Z-order apenas para colunas que aparecem em filtros; re-clustering reescreve dados e custa computação.
- Verifique a contagem de arquivos e o tamanho médio dos arquivos antes e depois; um trabalho de manutenção que não altera nenhum dos dois não fez nada.
- Execute vacuum ou remoção órfã em modo de teste primeiro onde o mecanismo oferecer.
6. MERGE, evolução de esquema, time travel
- MERGE: deduplique a fonte na chave de correspondência primeiro (correspondências duplicadas na fonte falham ou se aplicam duas vezes). Inclua um predicado de partição ou clustering na cláusula ON para que o mecanismo elimine arquivos em vez de escanear a tabela inteira.
- Prefira append mais MERGE periódico ou uma chave idempotente em vez de MERGE completo repetido em tabelas grandes.
- Evolução de esquema: colunas aditivas são seguras; renomeações e alargamento de tipo dependem do formato e versão (mapeamento de colunas no Delta, IDs de campo no Iceberg). Verifique o suporte nos leitores que importam antes de renomear. Nunca ative a mesclagem automática de esquema em uma entrada de pipeline de produção que você não controla.
- Time travel é uma ferramenta de depuração, auditoria e rollback, não um backup. Custa os arquivos retidos; quanto maior a retenção, mais armazenamento e metadados mais lentos. Defina a retenção deliberadamente e mantenha backups reais de tabelas críticas.
7. Fundamentos do PySpark 4.x
- Transformações são lazys; nada é executado até uma ação. Construa um plano, dispare uma escrita;
count()oushow()repetidos reexecutam o plano inteiro a menos que você faça cache deliberadamente. - Evite
collect(),toPandas()e.rddem dados grandes; eles puxam tudo para o driver. Limite ou agregue primeiro. - Use funções internas ou expressões SQL em vez de UDFs Python. UDFs bloqueiam o pushdown do otimizador e serializam linhas. Se inevitável, use uma UDF vetorizada (Arrow).
- Operações amplas (join, groupBy, window, distinct) sofrem shuffle. Filtre e projete antes delas; verifique o plano com
explain(). - Faça broadcast de um lado pequeno de um join (
broadcast(df)) quando ele couber na memória do executor; não faça broadcast de uma tabela ilimitada. - Adaptive Query Execution está ativado por padrão no Spark 4.x e lida com coalescência de partições, joins skew e troca de estratégia de join; ajuste após ler o plano, não antes.
- Skew aparece como uma tarefa lenta; salte ou isole a chave quente somente depois que AQE se mostrar insuficiente.
- Spark Connect é o modo cliente-servidor: o código é executado como um cliente leve em uma sessão remota. Não confie em elementos internos da JVM locais ao driver (
sparkContext, APIs RDD) no código Connect. - Escreva com um tamanho de arquivo alvo explícito via compactação, não por reparticionamento para um número adivinhado.
8. Caminho local primeiro
Desenvolva e teste no DuckDB ou polars antes de pagar por um cluster.
- DuckDB lê Delta e Iceberg por meio de extensões e anexa catálogos DuckLake; polars lê Delta e Iceberg de forma lazy com pushdown de predicados.
- Use uma amostra ou uma partição contra o layout real da tabela para que o comportamento de eliminação de arquivos corresponda.
- Confirme as semânticas de escrita (MERGE, vetores de exclusão, recursos v3) no mecanismo real; leitores locais podem ficar atrás dos recursos do formato. Trate uma leitura local bem-sucedida como necessária, não suficiente.
Procedimento
- Obtenha os números: tamanho, crescimento, escritores, leitores, mecanismos. 2. Percorra a seção 1; pare no ajuste mais barato. 3. Se lakehouse: escolha catálogo, depois formato (seções 4, 3). 4. Defina layout e um cronograma de manutenção antes da primeira carga. 5. Prototipe localmente (seção 8), depois execute no cluster com a saída de
explain()revisada. 6. Verifique com contagens de arquivos e planos de consulta, não suposições.
Armadilhas e correções conhecidas: veja references/gotchas.md.