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:
SELECTWHEREFROM<base table>UNION ALLQUALIFY[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 JOINOUTER JOINGROUP BYDISTINCTOVER(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;
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;
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;
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;
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;
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;
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;
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;
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. |