Como particionar tabelas Delta em ELT para consultas rápidas
Este guia mostra como particionar tabelas Delta em ELT para melhorar o desempenho das consultas e reduzir custos de leitura. Aprender a escolher a coluna de partição, criar a tabela particionada e optimizar ficheiros evita problemas como muitos ficheiros pequenos e partições desequilibradas.
Pré-requisitos
- Acesso a um ambiente que escreva/execute SQL sobre Delta (ex.: Databricks, Spark SQL).
- Dados brutos já carregados numa tabela/área de staging (ex.: mydb.raw_events).
- Permissões para criar tabelas e executar OPTIMIZE/VACUUM (se aplicável).
Passo 1: Escolher a coluna de partição certa
Porquê: uma má escolha cria partições com muitos ou poucos ficheiros e piora o desempenho. Boas práticas: preferir colunas com cardinalidade moderada e uso frequente em filtros (WHERE). Para dados temporais, usar datas (por dia, mês) é comum em ELT.
-- Exemplos de colunas a avaliar
-- COUNT(*) grouped para ver cardinalidade
SELECT event_date, COUNT(*) AS cnt
FROM mydb.raw_events
GROUP BY event_date
ORDER BY event_date DESC
LIMIT 50;
Passo 2: Criar a tabela Delta particionada
Explicação: criar a tabela em formato Delta e declarar PARTITIONED BY. Aqui fazemos um CTAS (CREATE TABLE AS SELECT) para materializar event_date derivada de um timestamp.
CREATE TABLE mydb.events_partitioned
USING delta
PARTITIONED BY (event_date)
AS
SELECT *, to_date(event_ts) AS event_date
FROM mydb.raw_events;
Passo 3: Carregar dados incrementais para a tabela particionada
Explicação: para ELT é comum fazer transformações no SELECT e inserir. Antes de inserir, reparticione o DataFrame/consulta por event_date para reduzir ficheiros pequenos. No Spark SQL/Databricks pode usar INSERT INTO com SELECT reparticionado via spark API (exemplo em PySpark) ou SQL com hint.
-- SQL simples (se o engine controlar escrita):
INSERT INTO mydb.events_partitioned
SELECT *, to_date(event_ts) AS event_date
FROM mydb.raw_events_incremental;
-- Exemplo PySpark para controlar número de ficheiros por partição:
df = spark.table('mydb.raw_events_incremental')
df = df.withColumn('event_date', to_date(col('event_ts')))
# Reparticionar por event_date para optimizar escrita por partição
df.repartition('event_date').write.format('delta').mode('append').saveAsTable('mydb.events_partitioned')
Passo 4: Compactar ficheiros e optimizar (compaction)
Problema comum: muitos ficheiros pequenos por partição. Solução: compactar usando OPTIMIZE (Databricks) ou escrever com coalesce antes de save. OPTIMIZE é útil em Delta para criar ficheiros maiores e reduzir overhead de metadata.
-- Exemplo Databricks: optimizar por tabela e, opcionalmente, ZORDER para colunas de consulta
OPTIMIZE mydb.events_partitioned
WHERE event_date = '2026-07-01';
-- Agregar manualmente com repartition/coalesce (antes de escrever nova carga)
df.repartition(1, 'event_date').write.format('delta').mode('overwrite').option('overwriteSchema','true').saveAsTable('mydb.events_partitioned')
Passo 5: Gerir evolução de partições e partições nulas
Erros comuns: inserções com event_date NULL criam diretórios _delta_log inesperados ou partições com valor NULL. Tratar NULLs durante a transformação e, se mudar a granularidade (dia→mês), criar nova coluna e backfill.
-- Filtrar ou substituir NULLs
INSERT INTO mydb.events_partitioned
SELECT *, coalesce(to_date(event_ts), date('1970-01-01')) AS event_date
FROM mydb.raw_events_incremental;
-- Para mudar partição (ex.: day -> month) cria-se nova tabela e CTAS com new_month
CREATE TABLE mydb.events_by_month
USING delta
PARTITIONED BY (event_month)
AS SELECT *, date_format(event_date,'yyyy-MM') AS event_month FROM mydb.events_partitioned;
Verificar o resultado
Executar queries e comandos de metadata para confirmar que as partições existem, ficheiros estão compactados e as consultas usam filtros de partição.
-- Ver partições existentes
SHOW PARTITIONS mydb.events_partitioned;
-- Ver detalhe da tabela Delta
DESCRIBE DETAIL mydb.events_partitioned;
-- Testar se o filtro usa apenas uma partição (EXPLAIN):
EXPLAIN SELECT COUNT(*) FROM mydb.events_partitioned WHERE event_date = '2026-07-01';
-- Verificar tamanho médio de ficheiros por partição (exemplo simplificado)
SELECT event_date, SUM(size) as total_bytes, SUM(file_count) as files
FROM (DESCRIBE HISTORY mydb.events_partitioned) -- se o engine expuser metadados
GROUP BY event_date ORDER BY event_date DESC LIMIT 20;
Conclusão
Particionar tabelas Delta em ELT melhora a latência e reduz custos quando feito com uma boa escolha de coluna, controlo de ficheiros e manutenção (OPTIMIZE/VACUUM). Próximos passos: medir o impacto com queries reais, automatizar compactação e testar a mudança de granularidade. Dica: comece por particionar por dia e monitorize a distribuição de ficheiros — tem dúvidas sobre qual granularidade usar para o teu volume?