<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Francisco Jaime da Silva</title>
    <description>The latest articles on DEV Community by Francisco Jaime da Silva (@francisco_jaimedasilva).</description>
    <link>https://dev.to/francisco_jaimedasilva</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3498192%2F11f4160d-fd55-42dd-a452-8f696e4acf7d.png</url>
      <title>DEV Community: Francisco Jaime da Silva</title>
      <link>https://dev.to/francisco_jaimedasilva</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/francisco_jaimedasilva"/>
    <language>en</language>
    <item>
      <title>Otimizando Escrita e Performance em Ambientes com Delta Lake, MinIO e Spark</title>
      <dc:creator>Francisco Jaime da Silva</dc:creator>
      <pubDate>Wed, 11 Mar 2026 02:01:36 +0000</pubDate>
      <link>https://dev.to/francisco_jaimedasilva/otimizando-escrita-e-performance-em-ambientes-com-delta-lake-minio-e-spark-1fme</link>
      <guid>https://dev.to/francisco_jaimedasilva/otimizando-escrita-e-performance-em-ambientes-com-delta-lake-minio-e-spark-1fme</guid>
      <description>&lt;p&gt;Quando lidamos com grandes volumes de dados em ambientes de Lakehouse, a eficiência na escrita e leitura faz toda a diferença. Usar o Delta Lake em conjunto com o Spark e armazenamentos como o MinIO abre possibilidades poderosas, mas também traz desafios: fragmentação de arquivos, lentidão em consultas e joins custosos. Neste artigo, compartilho estratégias práticas para lidar com esses problemas no dia a dia.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Otimizando escrita no Delta Lake com OPTIMIZE e Z-ORDER&lt;/strong&gt;&lt;br&gt;
Ao longo do tempo, tabelas Delta tendem a acumular muitos arquivos pequenos, o que degrada a performance das consultas. Para mitigar isso, o Delta Lake oferece o comando OPTIMIZE, que faz a compactação de arquivos em unidades maiores e mais eficientes para leitura.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OPTIMIZE:&lt;/strong&gt;&lt;br&gt;
Consolida vários arquivos pequenos em arquivos de tamanho ideal (normalmente entre 256MB e 1GB). Isso reduz o overhead de leitura e melhora a performance de scans completos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Z-ORDER:&lt;/strong&gt;&lt;br&gt;
Quando combinado ao optimize, o Z-ORDER organiza fisicamente os dados em disco de acordo com colunas de alto filtro nas consultas. Exemplo típico:&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;OPTIMIZE **ecommerce.transacoes **ZORDER BY *&lt;/em&gt;(cliente_id, data_compra);&lt;/p&gt;

&lt;p&gt;Isso melhora bastante consultas seletivas, já que os dados relacionados ficam próximos fisicamente, reduzindo I/O desnecessário.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Boas práticas:&lt;/strong&gt;&lt;br&gt;
Usar &lt;strong&gt;Z-ORDER&lt;/strong&gt; em colunas que mais aparecem nos filtros (&lt;strong&gt;WHERE&lt;/strong&gt;, &lt;strong&gt;JOIN&lt;/strong&gt;, &lt;strong&gt;GROUP BY&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automatizar a execução de OPTIMIZE em janelas de baixa carga, já que o processo consome recursos.&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reduzindo o problema de arquivos pequenos no MinIO
Ao escrever dados no MinIO (ou S3), o Spark pode gerar muitos arquivos pequenos devido ao paralelismo natural da execução. Isso não apenas ocupa espaço, mas também prejudica a performance de leitura quando usamo o Delta Lake.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Estratégias para lidar com o problema:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reparticionamento antes da escrita: Ajuste o número de partições antes do write para controlar quantos arquivos serão gerados:&lt;/p&gt;

&lt;p&gt;df.repartition(50).write.format(“delta”).mode(“append”).save(caminho)&lt;/p&gt;

&lt;p&gt;Aqui, 50 partições significa que a saída terá ~50 arquivos.&lt;/p&gt;

&lt;p&gt;Coalesce para dados menores: Quando o volume for reduzido após um filtro, use coalesce() para gerar menos arquivos.&lt;/p&gt;

&lt;p&gt;df.coalesce(1).write.format(“delta”).mode(“overwrite”).save(caminho)&lt;/p&gt;

&lt;p&gt;Auto Optimize e Auto Compact (quando disponíveis): No Databricks, recursos automáticos podem gerenciar esse problema, mas em ambientes com MinIO puro, vale mais a pena automatizar um job de OPTIMIZE periódico.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compactação pós-escrita:&lt;/strong&gt;&lt;br&gt;
Criar um job dedicado apenas para consolidar os arquivos pequenos, usando OPTIMIZE ou mesmo um processo customizado de merge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Particionamento e paralelismo no Spark para joins grandes&lt;/strong&gt;&lt;br&gt;
Outra dor comum em grandes volumes são os joins custosos, que muitas vezes resultam em shuffles pesados. Existem boas práticas para aliviar esse cenário:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Particionamento estratégico:&lt;/strong&gt;&lt;br&gt;
Particionar tabelas do Delta Lake por colunas usadas com frequência em filtros e joins. Exemplo:&lt;/p&gt;

&lt;p&gt;df.write.format(“delta”).partitionBy(“ano”, “mes”).save(caminho)&lt;/p&gt;

&lt;p&gt;Isso ajuda o Spark a ler apenas os arquivos relevantes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Broadcast join:&lt;/strong&gt; Se uma das tabelas for pequena o suficiente, é muito mais eficiente transmitir a tabela inteira para os executores:&lt;/p&gt;

&lt;p&gt;df_grande.join(broadcast(df_pequeno), “id”)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuração de paralelismo:&lt;/strong&gt;&lt;br&gt;
Ajustar o número de partições para o tamanho real do cluster:&lt;/p&gt;

&lt;p&gt;spark.config(“spark.sql.shuffle.partitions”, 400)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Valores muito baixos causam gargalo.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Valores muito altos geram overhead de arquivos pequenos. A ideia é sempre calibrar com base no cluster e no volume processado.&lt;/p&gt;

&lt;p&gt;Skew join handling: Em dados desbalanceados (ex.: muitos registros para um mesmo valor de chave), é comum que alguns executores fiquem sobrecarregados. O Spark possui configurações como:&lt;/p&gt;

&lt;p&gt;spark.conf.set(“spark.sql.adaptive.skewJoin.enabled”, “true”)&lt;/p&gt;

&lt;p&gt;Isso divide dinamicamente partições muito grandes, melhorando a distribuição de carga.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusão&lt;/strong&gt;&lt;br&gt;
O trio Delta Lake + Spark + MinIO é extremamente poderoso, mas para alcançar alta performance é essencial cuidar da forma como os dados são gravados e lidos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use OPTIMIZE e Z-ORDER para melhorar consultas seletivas.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lute contra arquivos pequenos ajustando particionamento e aplicando compactações periódicas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Planeje particionamento e paralelismo para reduzir o custo de joins e operações de shuffle.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Com essas práticas aplicadas de forma contínua, a diferença de performance é notável: menos tempo de processamento, custos menores e consultas mais ágeis para os consumidores de dados.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Este artigo é um trecho adaptado do livro&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Guia prático para construir um Data Lakehouse open source usando Minio , Delta Lake e Spark — Do Conceito à Prática com Ferramentas Open Source&lt;br&gt;
Disponível em breve na Amazon.&lt;/p&gt;

</description>
      <category>database</category>
      <category>dataengineering</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>O Poder da Leitura Genérica no PySpark: Uma Abordagem Unificada para Dados</title>
      <dc:creator>Francisco Jaime da Silva</dc:creator>
      <pubDate>Tue, 03 Mar 2026 16:41:59 +0000</pubDate>
      <link>https://dev.to/francisco_jaimedasilva/o-poder-da-leitura-generica-no-pyspark-uma-abordagem-unificada-para-dados-4lda</link>
      <guid>https://dev.to/francisco_jaimedasilva/o-poder-da-leitura-generica-no-pyspark-uma-abordagem-unificada-para-dados-4lda</guid>
      <description>&lt;p&gt;Em um mundo onde os dados estão espalhados em diferentes formatos e sistemas, a capacidade de lê-los de forma consistente é crucial para qualquer engenheiro ou cientista de dados. O PySpark, com sua API de leitura (spark.read), oferece uma solução elegante e poderosa para esse desafio, permitindo uma abordagem genérica que abstrai a complexidade subjacente de cada tipo de fonte de dados.&lt;/p&gt;

&lt;p&gt;O comando spark.read.format(formato).load(caminho) é a base dessa filosofia. Ele atua como uma porta de entrada universal, onde você especifica o formato dos dados (csv, parquet, json, delta) e o PySpark cuida do resto, seja lendo um arquivo simples ou acessando uma tabela complexa.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Como Funciona a Leitura Genérica?&lt;/strong&gt;&lt;br&gt;
A mágica por trás dessa abordagem está na estrutura flexível da API. Em vez de ter uma função separada para cada formato (como spark.read.csv()), o método format() direciona o PySpark para o “driver” de leitura correto.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A sintaxe é simples e direta:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Python&lt;/p&gt;

&lt;p&gt;df = spark.read.format(“formato”).option(“opcao1”, “valor1”).option(“opcao2”, “valor2”).load(“caminho_dos_dados”)&lt;br&gt;
format(“formato”): Este é o ponto de partida. Aqui, você diz ao Spark o tipo de dados que ele vai encontrar. Por exemplo, “csv”, “json”, “parquet”, “delta”, ou até mesmo um driver de banco de dados (“jdbc”).&lt;/p&gt;

&lt;p&gt;option(“chave”, “valor”): Os métodos option() são a chave para a customização. Eles permitem que você ajuste o comportamento da leitura para atender às necessidades específicas do seu arquivo. Isso pode incluir:&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;header: Para indicar se a primeira linha é um cabeçalho.&lt;br&gt;
*&lt;/em&gt;&lt;br&gt;
Subscribe to the Medium newsletter&lt;br&gt;
inferSchema: Para que o Spark tente adivinhar o tipo de dados de cada coluna (string, int, double, etc.).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;delimiter: Para especificar o separador de colunas em arquivos de texto.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;load(“caminho”): Finalmente, o método load() inicia a leitura. O caminho pode ser um diretório, um arquivo específico, ou até mesmo um caminho de um sistema de arquivos distribuído como HDFS ou S3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vantagens da Abordagem Unificada&lt;/strong&gt;&lt;br&gt;
Consistência e Padronização: O mesmo padrão de código pode ser usado para ler dados de diferentes fontes. Isso simplifica o desenvolvimento e a manutenção, pois a lógica de leitura se torna previsível e consistente em toda a sua base de código.&lt;/p&gt;

&lt;p&gt;Código Flexível e Reutilizável: A abordagem genérica é ideal para a criação de funções reutilizáveis, como a cita aqui nesse artigo. Em vez de escrever uma função para ler CSVs e outra para Parquet, você pode ter uma única função que aceita o formato como parâmetro, tornando seu código mais modular e escalável.&lt;/p&gt;

&lt;p&gt;Facilidade na Adição de Novas Fontes: Se sua equipe decidir usar um novo formato de dados, você não precisa reescrever toda a sua lógica de leitura. Basta adicionar uma nova opção para o parâmetro formato, e sua função genérica já estará pronta para lidar com a nova fonte.&lt;/p&gt;

&lt;p&gt;Suporte a Recursos Avançados: O spark.read não se limita a arquivos simples. Com ele, você pode aproveitar recursos poderosos como o Time Travel do Delta Lake, especificando versões (versionAsOf) ou timestamps (timestampAsOf) para acessar estados históricos da sua tabela. Isso é fundamental para auditoria, reprodução de dados e análise de mudanças.&lt;/p&gt;

&lt;p&gt;Em resumo, a leitura genérica no PySpark é mais do que uma conveniência; é um princípio de design que promove a escrita de código limpo, eficiente e robusto. Ao adotar essa abordagem, você simplifica suas pipelines de dados e capacita sua equipe a trabalhar com uma variedade crescente de dados de forma unificada e sem atritos.&lt;br&gt;
Apresentaremos aqui um exemplo de função pyspark para realizar a leitura dinamica de dados em vários formators, fique a vontande para realizar suas aptações:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fug9a0mc9p6cjfht5swmq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fug9a0mc9p6cjfht5swmq.png" alt=" " width="794" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este artigo é um trecho adaptado do livro&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guia prático para construir um Data Lakehouse open source usando Minio , Delta Lake e Spark&lt;/strong&gt; — Do Conceito à Prática com Ferramentas Open Source&lt;br&gt;
Disponível em breve na Amazon.&lt;/p&gt;

&lt;p&gt;Press enter or click to view image in full size&lt;/p&gt;

</description>
      <category>data</category>
      <category>dataengineering</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
