SELECTSELECT

SELECT

Como identificar tabelas não utilizadas no Snowflake

By Ian WhitestoneMar 19, 20235 min read

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

Embora os custos de armazenamento do Snowflake costumem representar uma fatia pequena do gasto total com a plataforma, muitos clientes têm um volume significativo de tabelas não utilizadas nas suas contas gerando cobranças desnecessárias. Se um dataset não está em uso, não traz valor para o negócio nem precisa ser armazenado por exigência legal, ele deve ser removido.

Remover datasets não utilizados é uma vitória rápida para times que querem cortar o gasto com Snowflake. Também ajuda na segurança e reduz os riscos de vazamento e exposição de dados. Quanto menos dados você armazena, menor a superfície para acessos indevidos.

Por fim, excluir tabelas não utilizadas melhora a usabilidade do data warehouse como um todo. Esses datasets costumam conter dados desatualizados ou que não deveriam ser acessados, então removê-los ajuda a evitar confusão e erros em relatórios.

Neste post, vamos mostrar como identificar tabelas não utilizadas no Snowflake usando a view access_history do Account Usage.

Se quiser pular direto para a implementação final em SQL, é só ir para o final!

A view Access History do Snowflake

A Access History é uma view do schema Account Usage do Snowflake Database, disponível para todas as contas Snowflake na edição Enterprise ou superior. Ela permite consultar quais objetos do Snowflake (tabelas, views e colunas) foram acessados por cada query, direta ou indiretamente.

Direct versus Base Objects Accessed

Para identificar quais colunas foram acessadas por uma query, há duas colunas que interessam: direct_objects_accessed e base_objects_accessed. A principal diferença entre elas está na forma como tratam views. Veja a definição de view a seguir:

create or replace view orders_view as (
	select *
	from orders
	where
		not test
		and success
);

A query select * from orders_view acessa diretamente o objeto orders_view e, indiretamente, a tabela base orders. Por isso, orders_view vai aparecer na coluna direct_objects_accessed do access_history, enquanto orders aparece em base_objects_accessed.

Na hora de decidir se uma tabela está em desuso, vale usar base_objects_accessed, já que ela leva em conta as queries que acessam a tabela indiretamente por meio de uma view.

Fazendo o parsing de base_objects_accessed

base_objects_accessed é um array JSON com todos os objetos de dados base acessados durante a execução da query. Veja um exemplo do conteúdo da coluna, retirado da documentação:

1[\
\
2  {\
\
3    "columns": [\
\
4      {\
\
5        "columnId": 68610,\
\
6        "columnName": "CONTENT"\
\
7      }\
\
8    ],\
\
9    "objectDomain": "Table",\
\
10    "objectId": 66564,\
\
11    "objectName": "GOVERNANCE.TABLES.T1"\
\
12  }\
\
13]

O array de objetos acessados por cada query pode ser transformado em uma linha por objeto com lateral flatten e, em seguida, filtrado para considerar apenas objetos do tipo tabela, como no exemplo abaixo:

with
access_history as (
    select *
    from snowflake.account_usage.access_history
),
access_history_flattened as (
    select
        access_history.query_id,
        access_history.query_start_time,
        access_history.user_name,
        objects_accessed.value:objectId::integer as table_id,
        objects_accessed.value:objectName::text as object_name,
        objects_accessed.value:objectDomain::text as object_domain,
        objects_accessed.value:columns as columns_array

Expandir código

Descobrindo quando uma tabela foi consultada/acessada pela última vez

Com o access_history "achatado" da query acima, dá para descobrir o momento exato em que uma tabela foi acessada pela última vez, além do usuário que executou a query:


with
access_history as (
    select *
    from snowflake.account_usage.access_history
),
access_history_flattened as (
    select
        access_history.query_id,
        access_history.query_start_time,
        access_history.user_name,
        objects_accessed.value:objectId::integer as table_id,
        objects_accessed.value:objectName::text as object_name,
        objects_accessed.value:objectDomain::text as object_domain,
        objects_accessed.value:columns as columns_array

Expandir código

Calculando os custos de armazenamento das tabelas

Ao identificar tabelas não utilizadas para excluir, ajuda muito ver os custos de armazenamento envolvidos. Com a view de Account Usage table_storage_metrics e considerando uma taxa de armazenamento de US$ 23 por terabyte por mês, dá para calcular o custo anual de armazenamento de cada tabela:

select
    id as table_id,
    table_catalog || '.' ||table_schema ||'.' || table_name as fully_qualified_table_name,
    (active_bytes + time_travel_bytes + failsafe_bytes + retained_for_clone_bytes)/power(1024,4) as total_storage_tb,
    -- Considera uma taxa de armazenamento de US$ 23/TB/mês
    -- Ajuste para o valor adequado conforme o seu contrato Snowflake
    total_storage_tb*12*23 as annualized_storage_cost
from snowflake.account_usage.table_storage_metrics
where
    not deleted

Identificando todas as tabelas não consultadas nos últimos X dias

Até aqui, vimos como descobrir quando uma tabela foi acessada pela última vez e os custos de armazenamento de cada uma. Agora dá para juntar essas peças e identificar todas as tabelas que não foram consultadas nos últimos 90 dias, mostrando a economia anual prevista caso elas sejam excluídas.

O SQL abaixo depende da view account_usage.access_history, disponível apenas para clientes Snowflake na edição Enterprise ou superior.

Se você usa dbt, vale conferir a versão alternativa deste SQL, que roda bem mais rápido.

with
access_history as (
    select *
    from snowflake.account_usage.access_history
),
access_history_flattened as (
    select
        access_history.query_id,
        access_history.query_start_time,
        access_history.user_name,
        objects_accessed.value:objectId::integer as table_id,
        objects_accessed.value:objectName::text as object_name,
        objects_accessed.value:objectDomain::text as object_domain,
        objects_accessed.value:columns as columns_array

Expandir código

Identificando tabelas não utilizadas com dbt

Consultar e achatar a view access_history pode ser bem lento pelo volume de dados a processar. Para queries mais rápidas sobre o histórico de acesso às tabelas, recomendamos materializar esses dados de forma incremental com o nosso pacote dbt open-source: dbt_snowflake_monitoring. Depois de instalado o pacote, as queries para identificar tabelas não utilizadas ficam muito mais simples. O código acima pode ser reescrito assim:

with
table_access_summary as (
    select
        table_id,
        max(query_start_time) as last_accessed_at,
        max_by(user_name, query_start_time) as last_accessed_by,
        max_by(query_id, query_start_time) as last_query_id
    from query_base_table_access
    group by 1
),
table_storage_metrics as (
	select
      id as table_id,
      table_catalog || '.' ||table_schema ||'.' || table_name as fully_qualified_table_name,
      (active_bytes + time_travel_bytes + failsafe_bytes + retained_for_clone_bytes)/power(1024,4) as total_storage_tb,

Expandir código

Descobrindo quando uma tabela foi atualizada pela última vez

Na hora de decidir se uma tabela deve ser excluída, pode ser útil saber quando ela foi atualizada pela última vez por uma operação DDL ou DML. A query abaixo mostra como encontrar todas as tabelas atualizadas na última semana usando a view tables do Account Usage:

select
    table_id,
    table_catalog||'.'||table_schema||'.'||table_name as fully_qualified_table_name,
    last_altered as last_altered_at
from snowflake.account_usage.tables
where
    last_altered > current_date - 7

Remover tabelas não utilizadas é uma das muitas oportunidades de economia ao alcance dos usuários do Snowflake. Além de revelar padrões de acesso a tabelas, o SELECT gera automaticamente diversas outras recomendações de otimização. Comece a usar hoje mesmo ou agende uma demo pelos links abaixo.

Ian Whitestone·Co-founder & CEO do SELECT

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