SELECTSELECT

SELECT

Query tags do Snowflake para monitoramento avançado

By Ian WhitestoneFeb 7, 20237 min read

Esta página também está disponível em English, Deutsch, Español, Français, Italiano e 日本語.

Os query tags do Snowflake permitem associar metadados arbitrários a cada query. Neste post, mostramos como usar query tags para ganhar mais visibilidade e monitoramento sobre os custos e a performance das suas queries no Snowflake.

O que é um query tag no Snowflake?

Query tags são um parâmetro opcional em nível de sessão que permite marcar qualquer instrução SQL do Snowflake com uma string. Podem ter até 2000 caracteres e conter qualquer caractere. Os valores de query tag de cada query ficam disponíveis na saída das views query_history do Snowflake, o que abre espaço para diversos casos de uso.

Vale destacar que query tags são diferentes de object tags. Os dois compartilham o propósito de viabilizar um monitoramento mais estruturado e melhorar a visibilidade dentro da sua conta Snowflake. Mas os object tags são usados em objetos persistentes da conta, como usuários, roles, tabelas, views, funções e muito mais.

Por que usar query tags no Snowflake?

Para a maioria dos usuários do Snowflake, os custos de compute das queries executadas em virtual warehouses respondem pela maior parte do gasto com o Snowflake. Apesar de ser possível atribuir o gasto de compute dentro de um warehouse a diferentes usuários calculando o custo por query, isso costuma não ser granular o suficiente, já que uma única conta de usuário em produção pode gerar a maior parte das queries — e dos custos.

Os query tags possibilitam uma atribuição de custos bem mais fina. Se você tem uma instrução SQL, ou uma sequência de instruções SQL associadas a um modelo de dados em um pipeline, basta atribuir o mesmo query tag a elas. Assim, os custos podem ser facilmente atribuídos a todas as queries vinculadas àquele tag. A alternativa seria agrupar por query_text, o que não permite juntar várias instruções SQL relacionadas no mesmo grupo — e essa abordagem cai por terra quando o texto SQL de um modelo de dados acaba sendo alterado, o que sempre acontece.

Os query tags também servem para um monitoramento mais granular da performance das queries. Seguindo o exemplo anterior, talvez você queira acompanhar o tempo total de execução de cada modelo de dados somando o tempo decorrido em todas as queries associadas. Ou, se um conjunto de queries alimenta dashboards voltados ao usuário final, os query tags abrem caminho para um monitoramento de performance mais direcionado.

Por último, os query tags permitem conectar queries a metadados de outros sistemas. Um query tag pode conter um dashboard_id, o que possibilita agregar todos os custos de um único dashboard e ainda cruzar com os metadados da ferramenta de BI para ver com que frequência aquele dashboard é acessado.

Como usar query tags no Snowflake

Definindo tags padrão

Query tags são um parâmetro em nível de sessão, mas dá para definir padrões nos níveis de conta e de usuário. Por exemplo:

1alter user shauna set query_tag = '{"team": "engineering", "user": "shauna"}';

A partir daí, toda query executada por esse usuário virá com esse tag padrão.

Definindo query tags em nível de sessão

Use o comando alter session para definir o query tag. Depois desse comando, todas as queries executadas na mesma sessão serão marcadas com essa string.

alter session set query_tag='users_model';

-- this query will be tagged with 'users_model'
create or replace table users_tmp as (
  select *
  from raw_users
  where
    not deleted
    and created_at > current_date - 1
);

-- this will also be tagged with 'users_model'
insert into users
from users_tmp
;

Expandir código

Recomendamos usar os padrões por usuário sempre que possível, para evitar chamadas frequentes de alter session, que adicionam latência à execução geral das queries.

Definindo query tags em Python

Se você usa Python para executar queries, há duas formas de definir query tags.

Definir uma vez na criação da conexão

Ao criar o objeto de conexão com o Snowflake Python Connector, dá para definir os parâmetros de sessão logo de cara. No exemplo abaixo, todas as queries executadas a partir desse objeto con serão marcadas com DATA_MODELLING_PIPELINE.

con = snowflake.connector.connect(
    user='XXXX',
    password='XXXX',
    account='XXXX',
    session_parameters={
        'QUERY_TAG': 'DATA_MODELLING_PIPELINE',
    }
)

Modificar manualmente via alter session

Se você não quer que todas as queries da sessão tenham o mesmo tag, pode rodar alter session set query_tag = 'XXX' antes de executar as queries em si.

con.cursor().execute("alter session set query_tag='users_model'")

query = """
create or replace table users_tmp as (
  select *
  from raw_users
  where
    not deleted
    and created_at > current_date - 1
)
"""

con.cursor().execute(query) # tagged with 'users_model'
con.cursor().execute("insert into users from users_tmp") # tagged with 'users_model'

Expandir código

Definindo query tags no dbt

Se você usa dbt, há três opções para definir query tags:

  1. Podem ser definidos uma única vez no seu profiles.yml ( fonte). Todas as queries executadas no seu projeto dbt serão marcadas com esse valor.
  2. Os tags podem ser definidos para todos os models de um determinado resource_path, ou para um único model, adicionando um +query_tag no seu dbt_project.yml. Para models individuais, também dá para especificar o query tag no config do model, ou seja, {{ config(query_tag = 'XXX') }}. Se um query tag padrão tiver sido definido no profiles.yml, ele será sobrescrito por qualquer um desses tags mais específicos.
  3. Você pode criar uma macro set_query_tag que define automaticamente o query tag com o nome do model para todos os models do seu projeto.

Consulte a documentação do dbt para ver exemplos de cada uma dessas opções, e fique atento ao possível modo de falha que eles mencionam: as queries podem acabar marcadas com um tag incorreto se ocorrerem certas falhas antes na cadeia.

Lançamos recentemente um novo pacote dbt, o dbt-snowflake-query-tags, para marcar todas as queries emitidas pelo dbt com um conjunto completo de metadados. Vale conferir.

Usando strings JSON

Ao definir query tags, recomendamos usar um objeto JSON pela facilidade de uso e pela consistência. Voltando ao exemplo de tagueamento de modelos de dados, podemos usar um objeto JSON para incluir informações extras, como o ambiente em que o model rodou, a versão, o gatilho de execução (foi uma execução agendada ou disparada manualmente?) e muito mais.

import json

query_tag = {
  'app_name': 'pipeline',
  'model_name': 'users',
  'environment': 'prod',
  'version': 'v1.2',
  'trigger': 'schedule'
}
con.cursor().execute(f"alter session set query_tag='{json.dumps(query_tag)}'")

con.cursor().execute(model_sql)

Como usar query tags para monitorar custos e performance no Snowflake

Os query tags aparecem nas views de query history para cada query_id. Veja um exemplo de query que mostra a performance média por query_tag:

Se o query_tag contiver um objeto JSON, dá para parseá-lo e segmentar por qualquer uma das chaves. Usando o exemplo acima:

select
    query_tag,
    count(*) as num_executions,
    avg(total_elapsed_time/1000) as avg_total_elapsed_time_s
from snowflake.account_usage.query_history
where
    start_time > current_date - 7
group by 1

Usando o pacote dbt-snowflake-monitoring

Se você usa o pacote dbt da SELECT para monitoramento de custos e performance, dá para analisar os custos por query tag além da performance:

select
    try_parse_json(query_tag)['model_name']::string as model_name,
    count(*) as num_executions,
    avg(total_elapsed_time/1000) as avg_total_elapsed_time_s
from snowflake.account_usage.query_history
where
    try_parse_json(query_tag)['app_name']::string = 'pipeline'
    and start_time > current_date - 7
group by 1

Você também vai perceber que essas queries rodam bem mais rápido do que uma query nas views de account usage do Snowflake, já que a tabela é materializada e ordenada por start_time para chegar a um estado bem clusterizado.

Usando query comments em vez de query tags

Outra prática comum para marcar queries é adicionar um comentário ao final 1 de cada query:

select
    try_parse_json(query_tag)['model_name']::string as model_name,
    count(*) as num_executions,
    sum(query_cost) as total_cost,
    avg(total_elapsed_time_s) as avg_total_elapsed_time_s
from query_history_enriched
where
    try_parse_json(query_tag)['app_name']::string = 'pipeline'
    and start_time > current_date - 7
group by 1

A vantagem é que essa abordagem funciona em qualquer data warehouse e é mais simples de implementar, já que não exige rodar um alter session. Outro ponto positivo é a performance, porque executar um alter session envolve uma chamada de rede de ida e volta até o Snowflake 2. Isso é tranquilo na maioria dos casos, mas pode não ser aceitável em aplicações em que 100 a 200 ms a mais no tempo de resposta fazem diferença. Por fim, como o texto da query pode chegar a 1MB, os query comments comportam muito mais metadados do que os query tags, limitados a 2000 caracteres.

Sempre que possível, recomendamos usar query tags, já que são bem mais simples de parsear e analisar depois. Se houver chance de os metadados da sua query ultrapassarem 2000 caracteres, vá de query comments.

Notas

  1. O Snowflake remove automaticamente qualquer comentário no início de cada query, então você precisa colocá-los no final.

  2. O comando alter session em si é extremamente rápido, levando cerca de 30 ms em média.

Ian Whitestone·Co-founder & CEO da SELECT

Ian é Co-founder e CEO da SELECT, uma plataforma SaaS de gestão e otimização de custos do Snowflake. Antes de fundar a SELECT, Ian passou 6 anos liderando times full stack de data science e engenharia na Shopify e na Capital One. Na Shopify, Ian liderou os esforços para otimizar o data warehouse e aumentar a observabilidade de custos.