Otimizar consultas para atualização incremental

Use esta página quando você projetar uma nova consulta de tabela dinâmica ou quiser otimizar uma existente para atualização incremental. Este guia mostra quais operadores têm bom desempenho, quais precisam de tratamento criterioso e como reestruturar as consultas para obter um melhor desempenho.

Para obter uma lista completa dos constructos de consulta compatíveis com a atualização incremental, consulte Consultas compatíveis para tabelas dinâmicas.

Expectativas de desempenho por operador

Antes de otimizar uma consulta de tabela dinâmica, saiba quais operadores se beneficiam da atualização incremental e quais podem causar problemas.

Nota

Consultas curtas (menos de 10 segundos) podem ter ganhos de desempenho menores devido a sobrecargas fixas, como otimização de consultas e cronograma de warehouse.

Operadores que apresentam bom desempenho de forma consistente

Estes operadores funcionam de maneira eficiente com a atualização incremental:

  • SELECT

  • WHERE

  • FROM <base table>

  • UNION ALL

  • QUALIFY [ RANK | ROW_NUMBER | DENSE_RANK ] … = 1

Para obter detalhes sobre como o Snowflake processa cada operador, consulte a tabela de referência de operadores.

Operadores afetados pela localidade de dados

Para esses operadores, o desempenho depende da localidade de dados, que é como você organiza os dados e onde ocorrem as alterações em relação às chaves:

  • INNER JOIN

  • OUTER JOIN

  • GROUP BY

  • DISTINCT

  • OVER (funções de janela)

Quando as alterações afetam apenas uma pequena parte das chaves de agrupamento ou de partição, esses operadores têm bom desempenho. Uma localidade de dados ruim ou alterações distribuídas por muitas chaves pode tornar a atualização incremental mais lenta do que a atualização completa.

Para obter detalhes sobre como o Snowflake processa cada operador, consulte a tabela de referência de operadores.

Padrões de otimização comuns

As seções a seguir mostram padrões comuns para otimizar consultas que utilizam operadores sensíveis à localidade.

Otimizar agregações

Quando você usa GROUP BY, o Snowflake recomputa as agregações de cada chave de agrupamento que contém alterações. O desempenho depende dos seguintes fatores:

  • Clustering de dados: os dados de origem clusterizados por chaves de agrupamento têm um melhor desempenho.

  • Alterar distribuição: procure alterações que afetem menos de 5% das chaves de agrupamento.

  • Complexidade de chaves: as referências de coluna simples superam as expressões compostas.

Problema: expressões compostas em chaves de agrupamento

Esta consulta tem um desempenho ruim porque a chave de agrupamento é uma expressão:

CREATE DYNAMIC TABLE hourly_sums
  TARGET_LAG = '1 hour'
  WAREHOUSE = my_warehouse
AS
  SELECT DATE_TRUNC('minute', ts), SUM(amount)
  FROM transactions
  GROUP BY 1;
Copy

Solução: materializar a expressão

Divida em duas tabelas dinâmicas para expor uma chave de agrupamento simples:

CREATE DYNAMIC TABLE transactions_with_minute
  TARGET_LAG = DOWNSTREAM
  WAREHOUSE = my_warehouse
AS
  SELECT DATE_TRUNC('minute', ts) AS ts_minute, amount
  FROM transactions;

CREATE DYNAMIC TABLE hourly_sums
  TARGET_LAG = '1 hour'
  WAREHOUSE = my_warehouse
AS
  SELECT ts_minute, SUM(amount)
  FROM transactions_with_minute
  GROUP BY 1;
Copy

Agora GROUP BY opera em uma coluna simples, e a tabela intermediária se beneficia da melhor localidade de dados.

Otimizar junções

O desempenho da junção depende de qual lado muda e como você clusteriza os dados.

INNER JOIN: o Snowflake une as alterações a partir do lado esquerdo à tabela direita, depois une as alterações a partir do lado direito à tabela esquerda. As junções têm bom desempenho quando um lado é pequeno ou muda com pouca frequência.

OUTER JOIN: o Snowflake também deve calcular valores NULL para linhas não correspondentes. O lado que muda afeta significativamente o desempenho.

Problema: tabela grande em ambos os lados com clustering ruim

Nenhuma tabela de origem é clusterizada por chave de junção:

CREATE DYNAMIC TABLE order_details
  TARGET_LAG = '1 hour'
  WAREHOUSE = my_warehouse
AS
  SELECT o.order_id, o.customer_id, p.product_name, o.quantity
  FROM orders o
  JOIN products p ON o.product_id = p.product_id;
Copy

Solução: clusterizar a tabela que muda com menos frequência

Clusterize a tabela de dimensões por chave de junção. Depois disso, a junção se beneficiará de uma melhor localidade:

ALTER TABLE products CLUSTER BY (product_id);

CREATE DYNAMIC TABLE order_details
  TARGET_LAG = '1 hour'
  WAREHOUSE = my_warehouse
AS
  SELECT o.order_id, o.customer_id, p.product_name, o.quantity
  FROM orders o
  JOIN products p ON o.product_id = p.product_id;
Copy

Para OUTER JOINs:

  • coloque a tabela que muda com mais frequência no lado LEFT.

  • Minimize as mudanças no lado oposto ao da palavra-chave OUTER.

  • Para FULL OUTER JOINs, uma boa localidade é fundamental nos dois lados.

Otimizar funções de janela

O Snowflake recomputa as funções de janela para cada chave de partição com alterações. Otimize-as de forma semelhante a GROUP BY.

Principais requisitos:

  • Sempre inclua uma cláusula PARTITION BY. Funções de janela sem PARTITION BY resultam em uma recomputação completa.

  • Clusterize os dados de origem por chaves de partição.

  • Mantenha as alterações em menos de 5% das partições.

Problema: função de janela sem clustering de partição

A tabela de origem não é clusterizada pela chave de partição:

CREATE DYNAMIC TABLE ranked_sales
  TARGET_LAG = '1 hour'
  WAREHOUSE = my_warehouse
AS
  SELECT
    region,
    salesperson,
    amount,
    RANK() OVER (PARTITION BY region ORDER BY amount DESC) as sales_rank
  FROM daily_sales;
Copy

Solução: clusterizar por chave de partição

Clusterize a tabela de origem por chave de partição para que a função de janela se beneficie da localidade:

ALTER TABLE daily_sales CLUSTER BY (region);

CREATE DYNAMIC TABLE ranked_sales
  TARGET_LAG = '1 hour'
  WAREHOUSE = my_warehouse
AS
  SELECT
    region,
    salesperson,
    amount,
    RANK() OVER (PARTITION BY region ORDER BY amount DESC) as sales_rank
  FROM daily_sales;
Copy

Remover duplicatas com eficiência (DISTINCT ou QUALIFY)

Ambos DISTINCT e QUALIFY podem remover duplicatas, mas eles funcionam de forma diferente.

DISTINCT: É equivalente a GROUP BY ALL. A localidade afeta diretamente o desempenho; uma localidade ruim causa atualizações lentas.

QUALIFY com ROW_NUMBER = 1: o Snowflake otimiza o padrão QUALIFY ROW_NUMBER() ... = 1 quando está na projeção de nível superior da tabela dinâmica. Esse padrão é executado de forma mais rápida e consistente do que a atualização completa.

A otimização funciona melhor quando todas as chaves PARTITION BY e ORDER BY na cláusula OVER() são persistentes na tabela dinâmica (incluídas na projeção de nível superior).

Recomendação: usar QUALIFY em vez de DISTINCT quando possível

O exemplo a seguir usa DISTINCT:

CREATE DYNAMIC TABLE unique_customers
  TARGET_LAG = '1 hour'
  WAREHOUSE = my_warehouse
AS
  SELECT DISTINCT customer_id, customer_name, email
  FROM customer_events;
Copy

O exemplo a seguir usa QUALIFY:

CREATE DYNAMIC TABLE unique_customers
  TARGET_LAG = '1 hour'
  WAREHOUSE = my_warehouse
AS
  SELECT customer_id, customer_name, email, event_time
  FROM customer_events
  QUALIFY ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY event_time DESC) = 1;
Copy

A versão QUALIFY é mais explícita em relação a qual duplicata manter (a mais recente) e tem um desempenho consistentemente bom.

Remover operações DISTINCT redundantes

Cada DISTINCT consome recursos a cada atualização. Quando seus dados já forem únicos ou você eliminar as duplicatas upstream, remova as cláusulas DISTINCT.

Referência de operadores

A tabela a seguir explica como o Snowflake processa cada operador SQL durante a atualização incremental:

Operador

Como o Snowflake o processa

Notas sobre desempenho

SELECT

Aplica expressões somente a linhas alteradas.

Bom desempenho. Nenhuma consideração especial.

WHERE

Avalia o predicado somente em linhas alteradas.

Bom desempenho. O custo aumenta de forma linear com as alterações. Nota: um WHERE altamente seletivo pode exigir tempo de atividade do warehouse, mesmo quando a saída não muda.

FROM <table>

Verifica as micropartições que o Snowflake adicionou ou removeu desde a última atualização.

O custo aumenta conforme o volume de partições alteradas. Limite as alterações a cerca de 5% da tabela de origem.

UNION ALL

Usa a união de alterações de cada lado.

Bom desempenho. Nenhuma consideração especial.

WITH (CTEs)

Computa alterações para cada expressão de tabela comum.

Bom desempenho, mas evita definições de tabela única excessivamente complexas. Considere dividir em várias tabelas dinâmicas.

Agregações escalares

Recomputa totalmente a agregação quando a entrada muda.

Evite em tabelas de desempenho crítico. Em vez disso, considere agrupar por uma constante.

GROUP BY

Recomputa as agregações para chaves de agrupamento alteradas.

Clusterize a fonte agrupando as chaves. Evite expressões compostas em chaves. Consulte Otimizar agregações.

DISTINCT

Equivalente a GROUP BY ALL.

Sensível à localidade. Considere o uso de QUALIFY em vez disso. Consulte Remover duplicatas com eficiência (DISTINCT ou QUALIFY).

Funções de janela

Recomputa em caso de chaves de partição alteradas.

Inclua sempre PARTITION BY. Clusterize a fonte por chaves de partição. Consulte Otimizar funções de janela.

INNER JOIN

Une as alterações de cada lado à outra tabela.

Bom desempenho quando um lado é pequeno. Clusterize o lado que muda com menos frequência. Consulte Otimizar junções.

OUTER JOIN

Combina uma junção interna com consultas NOT EXISTS para computação de NULL.

Operador mais sensível à localidade. Consulte Otimizar junções.

LATERAL FLATTEN

Aplica o nivelamento somente às linhas alteradas.

Bom desempenho. O custo aumenta de forma linear com as alterações.

QUALIFY com classificação

Usa um caminho otimizado para ROW_NUMBER/RANK/DENSE_RANK … = 1.

Altamente eficiente. Posicione o QUALIFY na projeção de nível superior da tabela dinâmica.