Armazene em cache os DataFrames em computação serverless

Importante

Este recurso está no Public Preview. Os administradores do espaço de trabalho podem controlar o acesso ao armazenamento em cache de DataFrame na computação sem servidor a partir da página Pré-visualizações. Ver Gerir as pré-visualizações de Azure Databricks.

Na computação serverless, pode armazenar em cache um DataFrame com df.cache() ou df.persist() para reutilizar um resultado caro na sua sessão. O Azure Databricks calcula o DataFrame quando chamar cache() e materializa o resultado como um snapshot. O DataFrame e os DataFrames que constróis a partir dele leem depois o snapshot durante o resto da tua sessão, em vez de o recalcularem.

Requirements

  • A pré-visualização da colocação em cache de DataFrames na computação serverless está ativada para o seu espaço de trabalho (ativada por defeito). Os administradores do espaço de trabalho podem desativá-lo a partir da página de Pré-visualizações . A pré-visualização não está disponível nos espaços de trabalho com o perfil de segurança de conformidade ativado. Veja Gerir pré-visualizações no nível do espaço de trabalho.
  • Notebooks e tarefas em computação serverless devem usar a versão do ambiente 5 ou superior.
  • O Databricks Connect para Python deve ser 18.1.8 ou superior, e o Databricks Connect para Scala deve ser 18.1.5 ou superior.

Os clientes mais antigos recebem o CACHE_REQUIRES_NEWER_CLIENT_ON_SERVERLESS_GC erro.

Quando usar cache DataFrame em computação serverless

Armazene em cache um DataFrame em computação serverless quando precisar:

  • Reutilize o resultado de uma junção, agregação ou filtro dispendioso várias vezes na mesma sessão.
  • Calcula um micro-batch em streaming uma vez numa função foreachBatch, depois escreve-o em vários destinos.
  • Treine ou ajuste vários modelos de aprendizagem automática com os mesmos dados de características preparados.
  • Mantém um snapshot estável enquanto executas vários passos de uma análise, mesmo que as tabelas de origem mudem.

Consulte Práticas recomendadas.

Coloque em cache as APIs de DataFrame em computação serverless

O exemplo seguinte armazena em cache um dia de encomendas associadas aos dados dos clientes, calcula a receita total do dia, adiciona a receita por região a uma tabela de relatórios e depois liberta a cache. Ambos os resultados leem o snapshot em cache em vez de executarem a junção novamente.

Python

from pyspark.sql import functions as F

# The DataFrame to cache: one day of orders joined with customer data.
oct_15_orders = (
    spark.table("main.sales.orders")
    .filter(F.col("order_date") == "2026-10-15")
    .join(spark.table("main.sales.customers"), "customer_id")
)
oct_15_orders.cache()

# Both results are built from oct_15_orders, so they read the cached snapshot.
total_revenue = oct_15_orders.agg(F.sum("amount")).first()[0]
print(f"Total revenue on 2026-10-15: {total_revenue}")

revenue_by_region = oct_15_orders.groupBy("order_date", "region").agg(F.sum("amount").alias("revenue"))
revenue_by_region.write.mode("append").saveAsTable("main.reports.revenue_by_region")

# Release the cache and the DataFrame when you no longer need it.
# oct_15_orders and DataFrames built from it can no longer be used.
oct_15_orders.unpersist()

Scala

import org.apache.spark.sql.functions._

// The DataFrame to cache: one day of orders joined with customer data.
val oct15Orders = spark.table("main.sales.orders")
  .filter(col("order_date") === "2026-10-15")
  .join(spark.table("main.sales.customers"), "customer_id")
oct15Orders.cache()

// Both results are built from oct15Orders, so they read the cached snapshot.
val totalRevenue = oct15Orders.agg(sum("amount")).first().get(0)
println(s"Total revenue on 2026-10-15: $totalRevenue")

val revenueByRegion = oct15Orders.groupBy("order_date", "region").agg(sum("amount").alias("revenue"))
revenueByRegion.write.mode("append").saveAsTable("main.reports.revenue_by_region")

// Release the cache and the DataFrame when you no longer need it.
// oct15Orders and DataFrames built from it can no longer be used.
oct15Orders.unpersist()

Nas descrições seguintes da API, df representa qualquer DataFrame na sua sessão, como oct_15_orders no exemplo anterior.

df.cache()

Calcula df imediatamente e guarda o resultado como um snapshot para o resto da tua sessão.

  • Devolve: O mesmo DataFrame em cache, df, agora baseado no snapshot em vez do cálculo nas suas tabelas de origem. Veja o seguinte comportamento.
  • Comportamento:
    • Executa imediatamente a consulta do DataFrame e materializa o resultado como um snapshot antes da chamada regressar.
    • Após a chamada, df e o DataFrame devolvido (df ele próprio) baseiam-se no snapshot. Já não estão ligados ao cálculo nas tabelas de origem, por isso leem a captura em vez de recalcularem a consulta.
    • DataFrames derivados de df, diretamente ou através de outros DataFrames derivados, leem automaticamente o snapshot em vez de executar novamente a consulta original. Veja Leia o instantâneo.
    • O snapshot é específico da tua sessão. Só a sessão que armazenou em cache df pode lê-lo. Ver Isolamento e privilégios.
    • A captura de estado dura até ao fim da sessão, no máximo sete dias. O Azure Databricks liberta automaticamente espaço de armazenamento em segundo plano. Chamar df.unpersist() permite libertar espaço de armazenamento mais cedo. Veja Ciclo de Vida e limites de tempo e Armazenamento e limpeza.
    • Se a computação df falhar, df.cache() gera o erro e df não é armazenado em cache.
    • Chamar df.cache() num DataFrame que já está em cache não faz nada. df não é calculado novamente.

O snapshot é fixado depois de chamar df.cache(). Os dados escritos depois nas tabelas que df lê, e as alterações de esquema nessas tabelas, como colunas adicionadas ou renomeadas, não o afetam. Para recalcular a partir dos dados mais recentes, constrói novamente o DataFrame a partir das tabelas de origem e guarda em cache o novo DataFrame se precisares.

Leia a captura instantânea

Na computação serverless, a correspondência de cache baseia-se na derivação DataFrame. Após df.cache(), apenas os seguintes DataFrames leem automaticamente o snapshot em vez de recalcular a consulta nas tabelas de origem:

  • O DataFrame que guardaste em cache, df.
  • DataFrames derivados de df, por exemplo com select(), filter(), groupBy(), ou join().
  • DataFrames adicionalmente encadeados a partir desses DataFrames derivados.

Um novo DataFrame que repete a mesma consulta lê as tabelas de origem, mesmo que a sua lógica seja idêntica, porque não é derivado de df.

Isto torna a correspondência de cache explícita e sob o seu controlo: um DataFrame lê dados em cache apenas quando os deriva de um DataFrame em cache. Cada DataFrame alternado lê as tabelas de origem.

Python

oct_15_orders = (
    spark.table("main.sales.orders")
    .filter(F.col("order_date") == "2026-10-15")
    .join(spark.table("main.sales.customers"), "customer_id")
)
# The join runs one time, when you call cache().
oct_15_orders.cache()

# Derived from oct_15_orders: read the snapshot, so the join doesn't run again.
large_orders = oct_15_orders.filter(F.col("amount") > 1000)
revenue_by_region = oct_15_orders.groupBy("order_date", "region").agg(F.sum("amount").alias("revenue"))

# Derived from large_orders, which is derived from oct_15_orders: also reads the snapshot.
large_orders_by_region = large_orders.groupBy("region").count()

# Not derived from oct_15_orders: reads the source tables and runs the join again.
same_query = (
    spark.table("main.sales.orders")
    .filter(F.col("order_date") == "2026-10-15")
    .join(spark.table("main.sales.customers"), "customer_id")
)

Scala

val oct15Orders = spark.table("main.sales.orders")
  .filter(col("order_date") === "2026-10-15")
  .join(spark.table("main.sales.customers"), "customer_id")
// The join runs one time, when you call cache().
oct15Orders.cache()

// Derived from oct15Orders: read the snapshot, so the join doesn't run again.
val largeOrders = oct15Orders.filter(col("amount") > 1000)
val revenueByRegion = oct15Orders.groupBy("order_date", "region").agg(sum("amount").alias("revenue"))

// Derived from largeOrders, which is derived from oct15Orders: also reads the snapshot.
val largeOrdersByRegion = largeOrders.groupBy("region").count()

// Not derived from oct15Orders: reads the source tables and runs the join again.
val sameQuery = spark.table("main.sales.orders")
  .filter(col("order_date") === "2026-10-15")
  .join(spark.table("main.sales.customers"), "customer_id")

Como df lê o instantâneo em vez dos DataFrames a partir dos quais foi construído, não podes referenciar as colunas de df através desses DataFrames. Consulte Limitações.

df.persist(storageLevel)

Um pseudónimo de df.cache() que aceita um nível de armazenamento.

  • Parâmetros:
    • storageLevel (opcional): Um StorageLevel, como StorageLevel.DISK_ONLY. A computação serverless aceita qualquer nível de armazenamento e ignora-o. O snapshot é armazenado da mesma forma para todos os níveis de armazenamento e df.storageLevel devolve StorageLevel.DISK_ONLY.

O valor de retorno e o comportamento são os mesmos que df.cache().

df.unpersist(blocking)

Liberta o snapshot em cache de df e destrói o DataFrame.

  • Parâmetros:
    • blocking (opcional): Ignorado. df.unpersist() Retorna imediatamente para um dos dois valores.
  • Retorna: O mesmo DataFrame, df, agora destruído.
  • Comportamento:
    • Marca o instantâneo como pronto a ser libertado. O Azure Databricks apaga então os dados em cache e liberta espaço de armazenamento em segundo plano.
    • Destrói df: df e quaisquer DataFrames anteriormente derivados dela já não são utilizáveis, e qualquer consulta subsequente sobre eles gera CACHE_DATAFRAME_ACCESS_AFTER_UNCACHE. Se guardar em cache um DataFrame derivado de df antes de chamar df.unpersist(), esse DataFrame mantém-se utilizável, porque tem o seu próprio snapshot.
    • Para continuar a trabalhar com a mesma fonte de dados, construa um novo DataFrame a partir da fonte de dados original, em vez de reutilizar o DataFrame não cacheado.
    • Chamar df.unpersist() num DataFrame que nunca foi armazenado em cache, ou do qual a cache já foi removida, é um no-op.

Chama df.unpersist() quando já não precisares dos dados em cache, por exemplo, quando nenhum passo posterior no teu notebook ou job os lê. Isto permite que o Azure Databricks liberte espaço de armazenamento mais cedo. Não uses df.unpersist() para atualizar dados. Para trabalhar com os dados mais recentes, constrói um novo DataFrame a partir das tabelas de origem.

Python

oct_15_orders = spark.table("main.sales.orders").filter(F.col("order_date") == "2026-10-15")
oct_15_orders.cache()
large_orders = oct_15_orders.filter(F.col("amount") > 1000)
orders_per_customer = oct_15_orders.groupBy("customer_id").count()
orders_per_customer.cache()  # Has its own snapshot.

# Acknowledge that the cached data is no longer needed.
# This releases the storage and destroys oct_15_orders.
oct_15_orders.unpersist()

oct_15_orders.count()  # Raises CACHE_DATAFRAME_ACCESS_AFTER_UNCACHE.
large_orders.count()  # Raises CACHE_DATAFRAME_ACCESS_AFTER_UNCACHE.
orders_per_customer.count()  # Reads its own snapshot.

# If you need the data again later, build a new DataFrame from the source tables.
oct_15_orders = spark.table("main.sales.orders").filter(F.col("order_date") == "2026-10-15")

Scala

var oct15Orders = spark.table("main.sales.orders").filter(col("order_date") === "2026-10-15")
oct15Orders.cache()
val largeOrders = oct15Orders.filter(col("amount") > 1000)
val ordersPerCustomer = oct15Orders.groupBy("customer_id").count()
ordersPerCustomer.cache() // Has its own snapshot.

// Acknowledge that the cached data is no longer needed.
// This releases the storage and destroys oct15Orders.
oct15Orders.unpersist()

oct15Orders.count() // Throws CACHE_DATAFRAME_ACCESS_AFTER_UNCACHE.
largeOrders.count() // Throws CACHE_DATAFRAME_ACCESS_AFTER_UNCACHE.
ordersPerCustomer.count() // Reads its own snapshot.

// If you need the data again later, build a new DataFrame from the source tables.
oct15Orders = spark.table("main.sales.orders").filter(col("order_date") === "2026-10-15")

df.storageLevel

Obtém o nível de armazenamento de df.

  • Retorna: StorageLevel.DISK_ONLY enquanto df está armazenado em cache. StorageLevel.NONE antes de o armazenar em cache e depois de chamar df.unpersist().

Python

from pyspark import StorageLevel

oct_15_orders.cache()
oct_15_orders.storageLevel == StorageLevel.DISK_ONLY  # True

Scala

import org.apache.spark.storage.StorageLevel

oct15Orders.cache()
oct15Orders.storageLevel == StorageLevel.DISK_ONLY // true

Para as assinaturas dos métodos, consulte a referência PySpark para cache, persist, unpersist e storageLevel.

Ciclo de vida e limites de tempo

Os dados em cache existem apenas dentro da sessão do Azure Databricks onde os guardas em cache. Torna-se inacessível quando a sessão termina, e dura no máximo sete dias. Após o limite de sete dias, usar um DataFrame em cache gera um erro em vez de ler novamente as tabelas de origem. Para voltar a fazer cache, inicie uma nova sessão.

Armazenamento e limpeza

O Azure Databricks gere automaticamente o armazenamento dos dados em cache. Os dados em cache são armazenados no armazenamento na cloud, com a localização específica dependendo do tipo de espaço de trabalho:

Depois de os dados em cache se tornarem inacessíveis, o Azure Databricks liberta automaticamente o espaço de armazenamento em segundo plano. Isto inclui casos em que a sessão termina devido a uma desconexão ou crash. Chamar df.unpersist() permite ao Azure Databricks recuperar o armazenamento mais cedo.

Isolamento e privilégios

Qualquer utilizador que consiga executar código em computação serverless pode armazenar em cache um DataFrame. Não precisas de privilégios extra.

Os dados em cache fornecem isolamento ao nível da sessão. Apenas a sessão que armazenou em cache um DataFrame pode ler os seus dados em cache. Outros utilizadores não conseguem aceder-lhe, incluindo outros utilizadores do mesmo bloco de notas.

Os dados em cache contêm aquilo que te foi permitido ler quando os colocaste em cache. Alterações de permissões, filtros de linhas e máscaras de coluna aplicadas às tabelas de origem depois não se aplicam aos dados em cache.

Melhores práticas

  • Cache quando precisar de um snapshot estável: Se executar várias transformações, agregações ou drill-downs nos mesmos dados calculados, o snapshot dá-lhes uma linha de base consistente que não muda quando as tabelas de origem mudam.
  • Armazene em cache cálculos caros, não leituras simples de tabelas: df.cache() materializa o resultado da consulta, e as leituras posteriores analisam esse instantâneo. Se colocares em cache uma leitura de tabela simples, como spark.table("main.sales.orders").cache(), as leituras posteriores ainda analisam uma cópia completa da tabela, por isso a cache poupa pouco. O cache compensa depois de trabalhos dispendiosos, como joins, agregações e filtros complexos.
  • Não armazene em cache dados que lê apenas uma vez: df.cache() calcula e armazena o resultado imediatamente, o que leva tempo e armazenamento. Se leres o resultado apenas uma vez, o custo inicial não compensa.
  • Use a cache ao derivar do DataFrame em cache: Para ler o instantâneo, construa operações posteriores a partir da variável DataFrame em cache, por exemplo df.select(...) ou df.filter(...). Um DataFrame independente construído a partir do mesmo cálculo nas tabelas de origem não utiliza a cache.
  • Não use cache para partilha de dados entre sessões ou entre utilizadores: Os dados em cache são privados e específicos da sua sessão. Outras sessões, cadernos, execuções de tarefas e utilizadores não o conseguem ler. Para partilhar resultados calculados entre sessões ou com outros utilizadores, escreva-os numa tabela permanente.
  • Mantenha as sessões com dados em cache abaixo dos sete dias: Veja Ciclo de Vida e limites de tempo. Se o teu fluxo de trabalho precisar dos dados por mais tempo, grava-os numa tabela da base de dados.
  • Chame df.unpersist() quando já não precisar dos dados em cache: Isto permite ao Azure Databricks libertar espaço de armazenamento mais cedo. Após a chamada, o DataFrame e os DataFrames derivados dele não podem ser usados.
  • Não usar df.unpersist() para atualizar dados: df.unpersist() termina a vida útil do snapshot. Para captar alterações nas tabelas de origem, constrói um novo DataFrame a partir das tabelas de origem.

Limitations

O armazenamento em cache de DataFrames na computação serverless apresenta as seguintes limitações:

  • Nomes e tipos de colunas: Os seguintes DataFrames não podem ser armazenados em cache. Renomeie ou faça cast das colunas antes de fazer cache, por exemplo com .alias("total_amount").
    • DataFrames com nomes de colunas duplicados.
    • DataFrames com nomes de colunas que contêm espaços ou qualquer um dos caracteres ,;{}()=, como sum(amount), resultante de uma agregação.
    • DataFrames com colunas de intervalo.
    • DataFrames com arrays, mapas ou structs que contêm valores do tipo NULL.
    • DataFrames sem colunas, ou apenas com colunas do tipo NULL.
  • Referências de colunas: Depois de armazenar em cache um DataFrame, não pode referenciar as suas colunas através dos DataFrames a partir dos quais foi construído. Por exemplo, após oct_15_orders = orders.join(customers, "customer_id") e oct_15_orders.cache(), oct_15_orders.select(orders.amount) aumenta CANNOT_RESOLVE_DATAFRAME_COLUMN. Use oct_15_orders.amount ou "amount" em vez disso.
  • APIs SQL e cache de catálogo: Instruções de cache SQL, como CACHE TABLE, e os métodos de cache de tabela de spark.catalog não são suportadas em computação serverless. Ver limitações da cache. Para reutilizar um resultado de consulta em SQL, utilize uma tabela temporária local de sessão.
  • Consultas de esquema de informação: Quando muitas sessões numa metastore armazenam em cache DataFrames, as consultas em information_schema.volumes e information_schema.schemata podem ser lentas ou com tempo de expiração. Filtrar volumes por catálogo não torna a consulta mais rápida. As queries em information_schema.tables não são afetadas.
  • Regiões Azure Government: A cache DataFrame não é suportada em computação serverless nas regiões Azure Government.

Migrar a partir do compute clássico

Para a maioria das cargas de trabalho, a cache na computação serverless dá os mesmos resultados que na computação clássica, e o código existente corre sem alterações. A tabela seguinte lista as diferenças.

Behavior Computação sem servidor Computação clássica
Correspondência da cache Apenas o DataFrame em cache e os DataFrames derivados dele usam automaticamente o cache. Qualquer consulta com a mesma forma do plano usa automaticamente a cache.
Atualidade dos dados Um snapshot consistente tirado no momento em que chama df.cache(). Varia: os dados em cache são atualizados em certos casos e fornecem uma versão instantânea noutros.
Âmbito da partilha Apenas para a tua sessão. Partilhado entre sessões dentro do cluster.
Materialização Eager: calculado imediatamente quando chamas df.cache(). Preguiçoso: calculado na primeira ação no DataFrame.
df.unpersist() Destrói o DataFrame e liberta o seu snapshot deterministicamente. Liberta a cache em memória. A utilização posterior do DataFrame pode usar dados mais recentes ou obsoletos, dependendo do produto e da fonte de dados.

Segue-se a descrição das duas primeiras diferenças com mais detalhe:

  • Correspondência da cache:
    • Cargas de trabalho afetadas pela mudança: A maioria das cargas de trabalho não é afetada. Se continuares a usar a variável DataFrame em cache, por exemplo com df.select(...) ou df.filter(...), a cache funciona como antes. A alteração afeta apenas cargas de trabalho onde uma consulta DataFrame ou SQL construída de forma independente reutiliza a cache porque tem a mesma forma do plano. Na computação serverless, essas consultas leem as tabelas de origem.
    • Se a sua carga de trabalho for afetada: Use a variável DataFrame em cache onde precisar do resultado em cache, em vez de construir a mesma consulta novamente.
  • Atualização dos dados:
    • Cargas de trabalho afetadas pela mudança: A maioria das cargas de trabalho não é afetada, porque ler novamente dados em cache após escrever nas suas tabelas de origem é incomum. A alteração afeta apenas cargas de trabalho que escrevem nas tabelas de origem e depois esperam que o DataFrame em cache mostre os novos dados.
    • Se a sua carga de trabalho for afetada: Depois de escrever nas tabelas de origem, construa um novo DataFrame a partir delas em vez de reutilizar o que está em cache.

Recursos adicionais