Otimizar tabelas delta

Concluído

O Spark é uma estrutura de processamento paralelo, com dados armazenados em um ou mais nós de trabalho. Além disso, os arquivos Parquet são imutáveis, com novos arquivos gravados para cada atualização ou exclusão. Esse processo pode resultar no armazenamento de dados pelo Spark em um grande número de pequenos arquivos, conhecido como o problema de arquivos pequenos. Isso significa que consultas sobre grandes quantidades de dados podem ser lentas ou até mesmo falhar ao serem concluídas.

Função OptimizeWrite

OptimizeWrite é um recurso do Delta Lake que reduz o número de arquivos à medida que eles são gravados. Em vez de gravar muitos pequenos arquivos, ele grava menos arquivos maiores. Isso ajuda a evitar o problema de arquivos pequenos e garante que o desempenho não seja degradado.

Diagrama mostrando como o Optimize Write grava menos arquivos maiores.

No Microsoft Fabric, OptimizeWrite está habilitado por padrão. Você pode habilitar ou desabilitar no nível da sessão do Spark:

# Disable Optimize Write at the Spark session level
spark.conf.set("spark.microsoft.delta.optimizeWrite.enabled", False)

# Enable Optimize Write at the Spark session level
spark.conf.set("spark.microsoft.delta.optimizeWrite.enabled", True)

print(spark.conf.get("spark.microsoft.delta.optimizeWrite.enabled"))

Observação

OptimizeWrite também pode ser definido nas Propriedades da Tabela e para comandos individuais de gravação.

Otimizar

Optimize é um recurso de manutenção de tabela que consolida pequenos arquivos Parquet em menos arquivos maiores. Você pode executar o Optimize após carregar grandes tabelas, resultando em:

  • menos arquivos maiores
  • melhor compactação
  • distribuição eficiente de dados entre os nós

Diagrama mostrando como o Optimize consolida arquivos Parquet.

Para executar o Optimize:

  1. No Lakehouse Explorer, selecione o menu ... ao lado do nome de uma tabela e selecione Manutenção.
  2. Selecione Executar comando OPTIMIZE.
  3. Opcionalmente, selecione Aplicar V-order para maximizar a velocidade de leitura no Fabric.
  4. Selecione Executar agora.

Função V-Order

Ao executar o Optimize, você pode optar por executar o V-Order, que é projetado para o formato de arquivo Parquet no Fabric. V-Order permite leituras extremamente rápidas, com tempos de acesso aos dados semelhantes ao de memória. Ele também melhora a eficiência de custos, reduzindo o uso de rede, disco e recursos da CPU durante as leituras.

V-Order vem habilitado por padrão no Microsoft Fabric e é aplicado enquanto os dados são gravados. Ele gera uma pequena sobrecarga de cerca de 15%, tornando as gravações um pouco mais lentas. No entanto, V-Order possibilita leituras mais rápidas a partir dos mecanismos de computação do Microsoft Fabric, como Power BI, SQL, Spark e outros.

No Microsoft Fabric, os mecanismos Power BI e SQL utilizam a tecnologia Microsoft Verti-Scan, que aproveita ao máximo a otimização V-Order para acelerar as leituras. O Spark e outros mecanismos não utilizam a tecnologia Verti-Scan, mas ainda assim se beneficiam da otimização V-Order, com leituras até 10% mais rápidas, chegando a 50% em alguns casos.

O V-Order funciona aplicando classificação especial, distribuição de grupo de linhas, codificação de dicionário e compactação em arquivos Parquet. Ele é 100% compatível com o formato Parquet de código aberto e todos os mecanismos Parquet podem lê-lo.

V-Order pode não ser benéfico para cenários intensivos de gravação, como repositórios de preparação de dados, em que os dados são lidos apenas uma ou duas vezes. Nesses casos, desabilitar o V-Order pode reduzir o tempo total de processamento para ingestão de dados.

Aplique o V-Order em tabelas individuais usando o recurso Manutenção de Tabela, executando o comando OPTIMIZE.

Captura de tela de manutenção de tabela com V-Order selecionado

Vacuum

O comando VACUUM permite remover arquivos de dados antigos.

Sempre que uma atualização ou exclusão é feita, um novo arquivo Parquet é criado e uma entrada é registrada no log de transações. Arquivos Parquet antigos são mantidos para possibilitar a viagem no tempo, o que significa que os arquivos Parquet se acumulam com o tempo.

O comando VACUUM remove arquivos de dados Parquet antigos, mas não remove os logs de transações. Quando você executa o comando VACUUM, não é possível fazer viagem no tempo para um período anterior ao tempo de retenção.

Diagrama mostrando como o comando VACUUM funciona.

Arquivos de dados que não estão atualmente referenciados no log de transações e que são mais antigos que o período de retenção especificado são excluídos permanentemente ao executar o VACUUM. Escolha seu período de retenção com base em fatores como:

  • Requisitos de retenção de dados
  • Tamanho dos dados e custos de armazenamento
  • Frequência de alterações nos dados
  • Requisitos regulatórios

O período de retenção padrão é de 7 dias (168 horas), e o sistema impede que você utilize um período de retenção menor.

Você pode executar o comando VACUUM de forma ad-hoc ou agendada usando notebooks do Fabric.

Execute o comando VACUUM em tabelas individuais utilizando o recurso de manutenção de tabela:

  1. No Lakehouse Explorer, selecione o menu ... ao lado do nome de uma tabela e selecione Manutenção.
  2. Selecione o comando Executar VACUUM usando o limite de retenção e defina o limite de retenção.
  3. Selecione Executar agora.

Imagem de tela mostrando as opções de manutenção da tabela.

Você também pode executar VACUUM como um comando SQL em um notebook:

%%sql
VACUUM lakehouse2.products RETAIN 168 HOURS;

O comando VACUUM é registrado no log de transações Delta, então você pode exibir execuções anteriores em DESCREVER O HISTÓRICO.

%%sql
DESCRIBE HISTORY lakehouse2.products;

Particionamento de tabelas Delta

O Delta Lake permite organizar dados em partições. Isso pode melhorar o desempenho, habilitando o esquema de dados ignorados, que aumenta o desempenho ao ignorar objetos de dados irrelevantes com base nos metadados de um objeto.

Considere uma situação em que grandes quantidades de dados de vendas estão sendo armazenadas. Você pode particionar os dados de vendas por ano. As partições são armazenadas em subpastas nomeadas como "ano=2021", "ano=2022", etc. Se você deseja relatar apenas os dados de vendas de 2024, então as partições de outros anos podem ser ignoradas, o que melhora o desempenho da leitura.

No entanto, o particionamento de pequenas quantidades de dados pode degradar o desempenho, pois aumenta o número de arquivos e pode exacerbar o "problema de pequenos arquivos."

Use particionamento quando:

  • Você tem grandes quantidades de dados.
  • As tabelas podem ser divididas em poucas partições grandes.

Não use particionamento quando:

  • Os volumes de dados são pequenos.
  • A coluna de particionamento tem alta cardinalidade, pois isso cria um grande número de partições.
  • Uma coluna de particionamento resultaria em múltiplos níveis.

Diagrama mostrando o particionamento por uma ou mais colunas.

As partições têm um layout de dados fixo e não se adaptam a diferentes padrões de consulta. Ao considerar o uso de particionamento, pense em como seus dados são usados e sua granularidade.

Neste exemplo, um DataFrame contendo dados de produtos é particionado por Categoria:

df.write.format("delta").partitionBy("Category").saveAsTable("partitioned_products", path="abfs_path/partitioned_products")

No Lakehouse Explorer, você pode ver que os dados são de uma tabela particionada.

  • Há uma pasta para a tabela, chamada "produtos_particionados."
  • Existem subpastas para cada categoria, por exemplo, "Categoria=Suportes para Bicicletas", etc.

Imagem da tela do Explorer do lakehouse e o arquivo de produto particionado por categoria.

Podemos criar uma tabela particionada semelhante usando SQL:

%%sql
CREATE TABLE partitioned_products (
    ProductID INTEGER,
    ProductName STRING,
    Category STRING,
    ListPrice DOUBLE
)
PARTITIONED BY (Category);