Dowiedz się, jak szybko zrozumieć koszt każdego produktu danych
Jeśli używasz Snowflake w produkcji i miesięczny rachunek ciągle rośnie, znasz to uczucie: suma jest wysoka, finanse zadają pytania, a jedyna odpowiedź brzmi „przetworzyliśmy więcej danych”. Ta odpowiedź jest bezużyteczna. „Więcej danych” nie jest czynnikiem kosztowym. Jest nim pipeline. Jest nim zespół. Jest nim źle zaprojektowany model. Jest nim zapomniany pełny refresh. Problem nie polega na tym, że Snowflake jest drogi. Problem polega na tym, że dla większości zespołów koszty Snowflake to czarna skrzynka bez żadnej atrybucji.
Ten artykuł koncentruje się na produkcyjnej atrybucji kosztów z użyciem Snowflake + dbt + Airflow, pokazując jak rozdzielić compute, tagować obciążenia i śledzić koszty per model, pipeline i zespół.

Całkowity koszt jest bezużyteczny. Potrzebujesz kosztu per produkt danych.
Większość organizacji monitoruje Snowflake tak: kredyty dziennie, kredyty per warehouse, może alerty przy skokach użycia. To dobry początek do planowania pojemności, ale nic nie daje w zakresie odpowiedzialności ani optymalizacji. Wiedza, że WH_TRANSFORM zużył wczoraj 2000 kredytów, nie mówi, który model to spowodował ani który zespół za to odpowiada.
Potrzebujesz kosztów podzielonych według tych samych granic, którymi projektujesz platformę. Jeśli myślisz w kategoriach domen, martów lub pipeline’ów, model kosztów powinien to odzwierciedlać. Praktycznie chcesz odpowiedzieć na pytania:
- Ile kosztuje „finance mart” miesięcznie?
- Które modele dbt są najdroższe?
- Który DAG Airflow zużywa najwięcej kredytów?
- Ile zużywa każdy zespół względem swojego budżetu?
- Co zmieniło się między ubiegłym a bieżącym miesiącem?
To unit economics dla Twojej hurtowni. Gdy je masz, optymalizacja kosztów staje się normalnym zadaniem inżynierskim: refaktoryzacja drogich modeli, zmiana materializacji, zmiana rozmiaru warehouse’ów. Bez nich działasz na ślepo.
Granularne tagowanie w dbt (QUERY_TAG jako warstwa metadanych)
Snowflake ma wbudowaną funkcję, która rozwiązuje 80% problemu: QUERY_TAG. Każde zapytanie może nieść metadane. Błąd większości zespołów to pozostawienie go pustego lub ustawienie statycznej wartości jak „dbt”. To nie daje nic.
Chcesz, żeby każde wykonanie modelu dbt automatycznie zawierało ustrukturyzowane metadane, takie jak:
- nazwa modelu
- schemat lub warstwa (staging/intermediate/marts)
- środowisko (dev/stage/prod)
- opcjonalnie domena lub zespół
To nie może polegać na pamiętaniu przez developerów o dodaniu configu. Musi być automatyczne i scentralizowane.
Przykładowe makro:
-- macros/query_tag.sql
{% macro build_query_tag(functionality = "default") %}
{% set tag = {
"model": this.name,
"schema": this.schema,
"env": target.name,
"functionality": functionality
} %}
{{ return(tag | tojson) }}
{% endmacro %}
Zastosuj je do konkretnych domen:
# dbt_project.yml
models:
+query_tag: "{{ build_query_tag() }}"
staging:
+query_tag: "{{ build_query_tag('staging') }}"
reporting:
+query_tag: "{{ build_query_tag('reporting') }}"
Potrzebujesz jeszcze większej elastyczności? Żaden problem — możesz ustawić query_tag w makrze {{ config }} na poziomie pliku modelu albo zrobić mapowanie functionality na podstawie „tagu” modelu. Granice są tylko w wyobraźni!
Od tego momentu każde zapytanie generowane przez dbt zapisuje ustrukturyzowany JSON w QUERY_TAG. W SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY możesz parsować te tagi i grupować koszty per model, warstwa lub środowisko. To skutecznie zamienia historię zapytań Snowflake w strumień zdarzeń bogaty w metadane, który analizujesz jak każdy inny dataset.

Bez tego kroku atrybucja na poziomie modelu jest prawie niemożliwa. Z nim dostajesz rozliczenie per model.
Tagowanie poza dbt (warstwa orkiestracji / Airflow)
dbt to tylko część obciążenia. Większość stacków ma też joby ingestii, backfille, skrypty Pythona, feature engineering i ad-hoc SQL. Jeśli tagujesz tylko dbt, nadal jesteś ślepy na dużą część wydatków.
Ta sama zasada: każda sesja powinna ustawiać sensowny QUERY_TAG.
W Airflow możesz ustawić parametry sesji przed uruchomieniem zapytań (jeśli używasz oficjalnego Snowflake SDK):
session_parameters={
"QUERY_TAG": '{"pipeline":"daily_ingestion","team":"data-platform"}'
}Lub jawnie:
cursor.execute("""
ALTER SESSION SET QUERY_TAG = '{"pipeline":"daily_ingestion","team":"data-platform"}'
""")Celem jest spójność. Każdy job powinien deklarować właściciela. Minimum: pipeline i zespół. Gdy to wymusisz, każdy kredyt zużyty w Snowflake ma dołączony kontekst. Nic nie działa anonimowo.
To pozwala później powiedzieć „ten konkretny DAG kosztuje 900 USD/mies.” zamiast „coś w ingestii jest drogie”.
Strategia warehouse’ów (izolacja compute)
Tagowanie daje separację logiczną. Warehouse’y dają separację fizyczną. Potrzebujesz obu.
Uruchamianie wszystkiego na jednym warehouse niszczy widoczność. Wszystkie zapytania dzielą ten sam pool compute, więc skoki się nakładają, a atrybucja się komplikuje. Uniemożliwia też niezależne skalowanie i tuning.
Lepsze podejście to podział warehouse’ów wzdłuż sensownych granic. Dwa popularne wzorce działają dobrze.
Oparte na typie obciążenia:
- loading / ingestia
- transformacja (dbt)
- raportowanie / BI
- ad-hoc / notebooki
Oparte na zespole/domenie:
- marketing
- finanse
- produkt
- data science
Zacznij prosto. Nawet rozdzielenie loadingu i transformacji zwykle daje duży zysk w przejrzystości. Po izolacji od razu odpowiesz na pytania wysokiego poziomu, np. czy transformacje czy ingestia generują większość kosztów, i możesz niezależnie zmieniać rozmiar lub harmonogram warehouse’ów.
Izolacja warehouse’ów poprawia też governance. Gdy zespół wie „to nasz warehouse i nasz rachunek”, zachowanie szybko się zmienia. Własność napędza optymalizację.
Raportowanie z ACCOUNT_USAGE
Gdy masz tagi i odizolowany compute, zostaje tylko agregacja. Snowflake już udostępnia wszystko w widokach systemowych.
Kluczowe źródła:
- QUERY_HISTORY — szczegóły wykonania zapytań i tagi
- WAREHOUSE_METERING_HISTORY — kredyty zużyte per warehouse i okno czasowe
Podejście jest proste: alokuj kredyty warehouse proporcjonalnie do zapytań i agreguj według tagów.
Uproszczony przykład:
with queries as (
select
query_id,
warehouse_name,
start_time,
total_elapsed_time,
parse_json(query_tag) as tag
from snowflake.account_usage.query_history
),
warehouse_usage as (
select
warehouse_name,
start_time,
credits_used
from snowflake.account_usage.warehouse_metering_history
)
select
tag:model::string as model,
tag:env::string as env,
sum(credits_used) as credits
from queries
join warehouse_usage
using (warehouse_name)
group by 1,2;
W praktyce dopracujesz logikę alokacji pod nakładające się zapytania, ale zasada zostaje: koszt staje się kolejną tabelą faktów. Możesz materializować marty takie jak:
- cost_per_model
- cost_per_pipeline
- cost_per_team
- daily_cost_trend
Wtedy analiza kosztów to zwykły SQL i dashboardy. Bez zgadywania.
Podsumowanie
Atrybucja kosztów Snowflake to nie problem narzędzia. To problem projektowy. Jeśli projektujesz wspólny compute bez metadanych, dostajesz zerową widoczność. Jeśli projektujesz tagowanie, izolację i ustrukturyzowaną agregację, koszt staje się mierzalny i zarządzalny.
Implementacja jest prosta: taguj wszystko, izoluj compute i zbuduj jeden mart kosztów. Potem nie tłumaczysz już rachunków finansom — pokazujesz im dokładnie, który produkt danych je wygenerował.
Joachim Hodana — inżynier oprogramowania i danych
No idea where your Data Warehouse spend goes? został pierwotnie opublikowany na Lortech Solutions Blog na Medium, gdzie rozmowa trwa dalej dzięki podświetleniom i odpowiedziom czytelników.


