Um Lakehouse mal particionado custa mais em consultas do que todo o processo de ingestão.
Na prática da bConcepts vemos isto repetidas vezes: equipas constroem pipelines que chegam aos dados sem pensar em como serão lidos. O resultado são milhares de ficheiros pequenos, scans desnecessários e relatórios lentos no Power BI. Neste artigo descrevemos, com passos concretos e métricas accionáveis, como definir uma estratégia de partição e políticas de compactação para um Lakehouse no Microsoft Fabric, incluindo heurísticas, exemplos numéricos e considerações operacionais para tornar estas decisões reproduzíveis e seguras.
Por que particionar um Lakehouse?
Particionar significa organizar os ficheiros físicos do Lakehouse em pastas (diretórios) que reflectem predicados de consulta frequentes — por exemplo, data, país ou categoria de produto. O ganho imediato é a chamada partition pruning: quando uma query filtra por data, o sistema só lê as pastas relevantes em vez de todos os ficheiros da tabela.

Sem partição adequada, até queries simples podem obrigar a ler terabytes de dados. Imagine uma tabela com 50 TB de histórico; um dashboard que filtra apenas o último mês pode, sem pruning, levar a ler 5–10 TB por execução. Se esse dashboard for refrescado 2.000 vezes por mês em DirectQuery, o custo cumulativo e a latência tornam‑se inaceitáveis. Em cenários práticos, vimos leituras desnecessárias que multiplicavam por 10 o consumo de vCore‑hours e aumentavam o tempo de resposta de 5 segundos para minutos.
Além do tempo de resposta e custos, há impacto operacional: mais ficheiros significam mais operações no catálogo, maior probabilidade de conflitos de I/O e mais complexidade na recuperação de falhas. Particionar adequadamente é uma das primeiras decisões de engenharia de dados com impacto directo na experiência do utilizador e nos custos mensais da plataforma.
Como escolher a chave de partição correta
Não existe uma chave «mágica». A escolha depende de dois factores principais: padrões de consulta (o que as BI queries filtram) e características do dado (cardinalidade e distribuição). Comece por analisar os relatórios e as queries: quais os filtros mais comuns? Data de evento, loja, país, utilizador, estado de processamento?
Algumas regras práticas que aplicamos em projectos cliente:
- Priorize colunas usadas em filtros frequentes por relatórios interactivos (ex.: data de evento, região). Se 70–90% das consultas filtram por mês, a partição por mês reduz substancialmente leituras.
- Evite partições por colunas de alta cardinalidade (ex.: ID do utilizador) — isto gera demasiadas pastas pequenas e perdas de eficiência. Como princípio, evite partições com mais de 10k a 100k valores distintos; para números de utilizadores na ordem dos milhões, não é boa ideia.
- Considere esquemas compostos (por exemplo, year=/month=) para dados temporais. Esta abordagem facilita operações de purga e manutenção: é simples remover year=2022 quando a retenção se aplica anualmente.
- Para filtros semi‑esperados (p.ex., país + categoria), avalie usar uma tabela materializada ou agregada em vez de partição composta que gere muitas pastas pouco utilizadas.
Exemplo: num sistema de e‑commerce, os relatórios de negócio normalmente filtram por mês e por país. Uma partição por year/month e, em complemento, colunas de filtro como country e category como colunas regulares (mas indexadas a nível de ordenação) tende a oferecer o melhor compromisso. Isto evita criar 200+ pastas por dia (se usasse dia) e garante que a maioria das queries parcela poucos diretórios.
Granularidade, cardinalidade e impacto em queries
A granularidade das partições é um trade‑off entre selectividade (quantas pastas são lidas) e overhead de metadata/ficheiros. Partições demasiado finas levam ao problema dos "small files": centenas de milhares de ficheiros pequenos que degradam I/O e aumentam latência. Partições demasiado grossas perdem selectividade e obrigam a ler mais dados do que o necessário.
Indicadores que monitorizamos para ajustar granularidade:
- Número de ficheiros por partição: se uma partição tiver >10k ficheiros, suspeite do problema dos small files. Em muitos casos, objectivamos ter no máximo 1k–2k ficheiros por partição, dependendo do tamanho total de dados.
- Tamanho médio de ficheiro: ideal entre 128 MB e 512 MB para ficheiros parquet/Delta em cenários analíticos. Valores médios abaixo de 50 MB são sinal de alerta; abaixo de 20 MB é geralmente insustentável a longo prazo.
- Bytes lidos por query: avalie quantos GB são lidos em relatórios críticos. Se um KPI necessita apenas de 50 MB de dados agregados e a query lê 50 GB, a partição (ou o design dos dados) precisa de revisão.
Uma heurística útil: se 80% das consultas filtram por mês, adopte month‑partitions; se muitas queries filtram por hora (ex.: pipelines de streaming e alerting), combine partições por dia e crie índices auxiliares ou tabelas agregadas para cenários de low‑latency. No caso de dados de telemetria com 100M eventos/dia, uma partição diária com compactação agressiva para ficheiros de ~256 MB é uma configuração comum.
Compactação: quando, como e com que objetivos
Compactação (ou "compaction") é o processo de reescrever ficheiros pequenos em ficheiros maiores e ordenados, reduzindo a contagem de ficheiros e melhorando leitura sequencial. O objectivo não é apenas reduzir ficheiros: é optimizar a leitura física e, quando faz sentido, melhorar a ordenação dos dados (z‑ordering) para acelerar filtragem multidimensional e reduzir o volume lido.
Quando compactar?
- Após cargas massivas que geram muitos ficheiros pequenos (ex.: ingestões por stream ou por micro‑batches). Por exemplo, se uma ingestão diária de 1 TB resulta em 20k ficheiros, está na hora de compactar.
- Quando o tamanho médio do ficheiro numa partição estiver abaixo de 50 MB — plano de acção: reescrever até atingir 128–512 MB por ficheiro.
- Quando o número de ficheiros por partição for superior a 5k–10k ou quando a latência dos relatórios aumenta de forma consistente.
Estratégias de compactação:
- Compactação incremental (minor compaction): junta pequenos ficheiros dentro de uma partição para reduzir contagem de ficheiros sem reescrever toda a partição. Útil quando os dados são append‑heavy e se pretende minimizar custo de reescrita.
- Compactação completa (major compaction): reescreve a partição inteira para definir um novo layout e aplicar ordenação/Z‑order. Mais custosa, mas necessária periodicamente para reorganizar dados sobre longos períodos.
- Ordenação por coluna (z‑order): quando queries combinam filtros multidimensionais (ex.: data + user_id + product_id), ordenar por colunas com alta selectividade pode reduzir muito o volume lido. Avalie custo/benefício — ordenar é custoso em CPU.
Como compactar com segurança:
- Faça compactações idempotentes: read -> repartition/coalesce -> write (modo atomic). Teste numa partição pequena antes de generalizar. Evite operações que introduzam inconsistências no catálogo.
- Reserve janelas de baixa utilização para compactações pesadas, ou use autoscaling para minimizar impacto sobre consultas interactivas. No Fabric, é comum correr compactações fora do horário de pico ou em clusters temporários dimensionados para a tarefa.
- Use políticas de retenção e VACUUM (remover ficheiros obsoletos) após operações de rewrite para não inflar armazenamento. Por exemplo, após um major compaction, correr VACUUM com retenção de 7 dias (ou conforme política) para remover ficheiros antigos e garantir integridade de backups/retentores).
Compactar não é magia: é a tradução de know‑how operacional em tempo de resposta e poupança de custos.
Implementação prática no Microsoft Fabric
No Microsoft Fabric dispomos de ferramentas integradas para implementar as estratégias descritas: lakehouses (OneLake), notebooks Spark, pipelines e orquestração. O fluxo típico que recomendamos segue fases claras:
- Definir esquema de partições ao criar a tabela no Lakehouse (por exemplo, partitioned by (year, month)). Documente essa decisão no catálogo e nos runbooks.
- Ingerir dados em modo append para pastas temporárias ou staging para evitar ficheiros demasiado pequenos directamente na partição final. Agrupe micro‑batches antes de promover para a partição final.
- Agendar um job de compactação (Spark notebook) que leia partições alvo e reescreva ficheiros com coalesce/repartition para o número de ficheiros desejado, alinhado com o target de tamanho por ficheiro (~256 MB).
- Executar operações de manutenção: VACUUM para Delta (ou equivalente), e actualizar metadados do catálogo. Automatize alertas quando métricas ultrapassarem thresholds.
Exemplo de snippet técnico (escrito de forma genérica):
spark.read.format("delta").load("/oneLake/cliente/events/year=2026/month=08") .repartition(50) .write.mode("overwrite").format("delta").option("overwriteSchema", "true") .save("/oneLake/cliente/events/year=2026/month=08")
Notas práticas:
- Escolha o número de partições finais com base no target de tamanho (ex.: escolher repartition(50) porque o volume da partição é ~12 TB e 12 TB / 50 ≈ 240 GB por ficheiro colectivo, daí ajustar para obter ~256 MB por ficheiro).
- Use pipelines do Fabric para orquestrar notebooks e monitorizar falhas — por exemplo, compactar apenas partições com mais de N ficheiros e com tamanho médio <50 MB.
- Registe métricas (número de ficheiros, tamanho médio, tempo de compactação) em tabelas de meta‑operacionais para análise histórica e tuning. Um painel simples com thresholds (ficheiros >5k, avg_size <50 MB, tempo >2h) evita regressões.
Mini‑caso prático: retalho online que reduz latência e custos
Contexto: uma empresa de retalho online com 120 colaboradores processa eventos de compra e navegação. Ingestão: 200 milhões de eventos por mês (≈2,4 TB de parquet / mês). Antes da intervenção, cada ingestão diária produzia ficheiros médios de 6 MB, totalizando 400k ficheiros por mês para a tabela de eventos.
Problema observado:
- Relatório diário de vendas (Power BI, DirectQuery) demorava em média 90s a carregar e era executado ~3.000 vezes/mês por analistas e dashboards automatizados.
- Leitura média por execução: 150 GB de dados lidos, com custos de processamento elevados e experiências de utilizador pobres.
Intervenção implementada em 4 semanas:
- Definição de partições por year/month/day e reconfiguração do processo de ingestão para escrever primeiro numa pasta staging. Reduzimos escrita directa nas partições finais e agregámos micro‑batches.
- Compactação diária de cada partição que passou a gerar ficheiros médios de 250 MB (utilizando notebooks Spark orquestrados por pipelines do Fabric). Implementámos minor compactions contínuas e um major compaction semanal para partições activas.
- Política de limpeza: VACUUM para remover ficheiros obsoletos e retenção de 365 dias em partições antigas; definimos alertas para partições com avg_size <50 MB.
Resultados mensuráveis em produção (30 dias depois):
- Número de ficheiros mensais reduzido de 400k para 8k (–98%).
- Tamanho médio do ficheiro aumentou de 6 MB para 250 MB.
- Tempo médio do relatório diário caiu de 90s para 8s (–91%).
- Bytes lidos por execução caíram de 150 GB para 12 GB (–92%).
- Consumo de vCore‑hours do cluster de consultas partilhadas reduziu‑se de 1.200 vCore‑h/mês para 300 vCore‑h/mês (–75%), depois de considerar o overhead de compactação.
Impacto no negócio: os analistas passaram a explorar dados de forma mais fluida, o SLA de refresh de dashboards melhorou e o custo mensal associado a consultas analíticas diminuiu significativamente, justificando a automação da compactação. Mesmo quando contabilizamos o custo das jobs de compactação (por exemplo, 40 vCore‑h/mês extra), o ganho líquido foi substancial — tanto em performance como em custo.
Em resumo
- Particione por padrões de consulta: priorize colunas que as BI queries usam em filtros frequentes; para dados temporais, use year/month em vez de dia quando relevante.
- Mantenha ficheiros grandes o suficiente (128–512 MB) para optimizar I/O e reduzir overhead de metadata; compacte quando avg size <50 MB ou ficheiros por partição >5k–10k.
- Automatize compactações com notebooks Spark e pipelines do Fabric, monitorizando métricas de ficheiros e tempo de execução para ajustar frequência e evitar regressões.
- Balanceie custos: compactação consome compute, mas reduz leituras repetidas e latências, frequentemente gerando economias líquidas mensais e melhor experiência para utilizadores.
Conclusão e próximos passos: a estratégia técnica que descrevemos deve ser tratada como iterativa. Comece por mapear padrões de consulta, implemente partições conservadoras (ex.: year/month), automatize compactação para partições problemáticas e acompanhe as métricas operacionais. No Microsoft Fabric, a integração entre lakehouses, notebooks e pipelines facilita esta operacionalização — mas é a disciplina (agendamento, tracking, thresholds) que a torna sustentável.
Que partições estão a causar mais leituras na sua organização hoje — e que pequena mudança poderia reduzir a latência dos seus dashboards já amanhã?