Optymalizacja kosztów BigQuery w pipeline danych finansowych. Partycjonowanie, sloty i kontrola budżetu.

Jerzy Kopaczewski 24 lipca 2026 13 min czytania
Contents

Optymalizacja kosztów BigQuery w pipeline danych finansowych

BigQuery w modelu on-demand kosztuje $6.25 za każdy terabajt przetworzonych danych. Dla finansowego pipeline, który przelicza dzienne pozycje portfela, generuje raporty regulacyjne i zasila panele analityczne, to może oznaczać tysiące dolarów miesięcznie - nawet jeśli same dane zajmują zaledwie kilkadziesiąt gigabajtów. Problem nie leży w rozmiarze danych, ale w sposobie ich odpytywania. Ten artykuł pokazuje konkretne techniki, które obniżają rachunki za BigQuery o 40-70% bez utraty szybkości zapytań.

W polskim sektorze fintech i usług finansowych BigQuery staje się standardem dla analitycznych procesów przetwarzania danych. Firmy przetwarzają dane transakcyjne, generują raporty dla KNF, obliczają wskaźniki ryzyka i zasilają modele scoringowe. Wszystko to na danych, które mają naturalną strukturę czasową (data transakcji, dzień rozliczeniowy) i wymiarową (klient, produkt, waluta) - co oznacza, że BigQuery można zoptymalizować bardzo agresywnie, jeśli się wie jak.

 

Jak BigQuery nalicza opłaty

BigQuery oferuje dwa modele cenowe:

ModelOpłataKiedy opłacalny
On-demand$6.25/TB przetworzonych danychSporadyczne zapytania, mały zespół, prototypy
Editions (sloty)Od $0.04/slot/godzinę (Standard), autoscalingRegularne pipeline, duże zespoły, przewidywalne obciążenie

Kluczowa zasada: W modelu on-demand płacisz za ilość danych, którą zapytanie SKANUJE - nie za ilość wyników. Zapytanie SELECT * FROM transactions WHERE date = '2026-07-01' na niepartycjonowanej tabeli 500 GB skanuje 500 GB, nawet jeśli zwraca 1 GB danych.

To oznacza, że każda optymalizacja, która ogranicza ilość skanowanych danych, bezpośrednio obniża koszt.

 

Partycjonowanie - fundamentalna optymalizacja

Co to jest i dlaczego jest krytyczne

Partycjonowanie dzieli tabelę na segmenty fizyczne po wybranej kolumnie (najczęściej dacie). BigQuery skanuje tylko partycje, które spełniają warunek WHERE - reszta jest pomijana.

Dla danych finansowych partycjonowanie po dacie transakcji to absolutne minimum. Bez tego każde zapytanie dzienne skanuje całą tabelę historyczną.

Przykład: tabela transakcji

-- Tabela BEZ partycjonowania (zły wzorzec)
CREATE TABLE `project.dataset.transactions` (
  transaction_id STRING,
  account_id STRING,
  amount NUMERIC,
  currency STRING,
  transaction_date DATE,
  category STRING
);

-- Zapytanie dziennego raportu skanuje CAŁĄ tabelę (np. 2 TB = $12.50)
SELECT account_id, SUM(amount) 
FROM `project.dataset.transactions`
WHERE transaction_date = '2026-07-01'
GROUP BY account_id;
-- Tabela Z partycjonowaniem (właściwy wzorzec)
CREATE TABLE `project.dataset.transactions`
(
  transaction_id STRING,
  account_id STRING,
  amount NUMERIC,
  currency STRING,
  transaction_date DATE,
  category STRING
)
PARTITION BY transaction_date
CLUSTER BY account_id, currency;

-- To samo zapytanie skanuje TYLKO partycję 2026-07-01 (np. 5 GB = $0.03)
SELECT account_id, SUM(amount)
FROM `project.dataset.transactions`
WHERE transaction_date = '2026-07-01'
GROUP BY account_id;

Oszczędność: z $12.50 na $0.03 - redukcja o 99.8% (przy 2 TB tabeli z dziennymi partycjami po ~5 GB).

Strategie partycjonowania dla danych finansowych

Typ danychPartycjonowanieClustering
TransakcjePARTITION BY transaction_dateCLUSTER BY account_id, currency
Pozycje portfela (EOD)PARTITION BY valuation_dateCLUSTER BY fund_id, instrument_type
Dane rynkowe (ticki)PARTITION BY DATE(timestamp)CLUSTER BY symbol, exchange
Raporty regulacyjnePARTITION BY reporting_dateCLUSTER BY entity_id, report_type
Logi audytowePARTITION BY DATE(event_time)CLUSTER BY user_id, action

Wymuszanie użycia partycji (partition filter required)

Dla tabel, gdzie ktoś może przypadkowo zapomnieć o filtrze daty:

ALTER TABLE `project.dataset.transactions`
SET OPTIONS (require_partition_filter = true);

Teraz zapytanie bez WHERE transaction_date = ... zakończy się błędem zamiast skanować całą tabelę. To zabezpieczenie przed przypadkowym wydatkiem $12 na jedno zapytanie.

 

Clustering - druga warstwa optymalizacji

Clustering sortuje dane wewnątrz partycji po wybranych kolumnach (max 4). BigQuery pomija bloki danych, które nie pasują do warunków WHERE na kolumnach użytych w clustering.

Kiedy clustering daje największe oszczędności:

  • Zapytania często filtrują po account_id, currency lub instrument_type
  • Tabela ma miliony wierszy na partycję
  • Kolumna clustering ma rozsądną kardynalność (100-100,000 unikalnych wartości)

Kiedy clustering nie pomoże:

  • Zapytania zawsze skanują całą partycję (np. agregacja na dzień bez filtrów)
  • Kolumna ma zbyt niską kardynalność (np. 3 wartości - lepsze jako PARTITION BY)
  • Kolumna ma zbyt wysoką kardynalność (np. UUID - brak sensownego grupowania)

 

Materialized Views - cache dla powtarzalnych zapytań

Pipeline’y finansowe mają przewidywalny wzorzec: te same agregacje są przeliczane codziennie (dzienne pozycje, sumy per klient, sumy per waluta). Materialized Views zapisują wynik agregacji i automatycznie go odświeżają.

CREATE MATERIALIZED VIEW `project.dataset.daily_account_summary`
AS
SELECT
  transaction_date,
  account_id,
  currency,
  SUM(amount) AS total_amount,
  COUNT(*) AS transaction_count
FROM `project.dataset.transactions`
GROUP BY transaction_date, account_id, currency;

Jak to oszczędza pieniądze:

  • Zapytania, które pasują do wzorca materialized view, czytają z view (mniejszy skan)
  • BigQuery automatycznie routuje zapytania do view, jeśli uzna, że to możliwe
  • Koszt odświeżania view: inkrementalny (tylko nowe dane), nie pełny reskan

Typowa oszczędność: 50-80% na powtarzalnych zapytaniach analitycznych.

 

BI Engine - cache w pamięci dla dashboardów

Jeśli Twój zespół korzysta z Looker Studio (dawniej Data Studio) lub Tableau podłączonego do BigQuery, BI Engine utrzymuje dane w pamięci RAM:

  • Koszt: od $2.50/GB/godzinę rezerwacji (minimum 1 GB)
  • Efekt: każdy dashboard odpowiada w milisekundach zamiast sekund
  • Oszczędność: zapytania z BI Engine nie zużywają slotów ani bajtów on-demand

Dla zespołu 10-20 analityków, którzy odświeżają każdy dashboard kilkadziesiąt razy dziennie, BI Engine z rezerwacją 5-10 GB ($12-25/godzinę roboczą) jest tańszy niż on-demand skanowanie tych samych danych setki razy.

 

Model Editions (sloty) vs on-demand - kiedy się przełączyć

Przeliczanie progu opłacalności

On-demand: $6.25/TB Standard Edition: $0.04/slot/godzinę (autoscaling, bez zobowiązania)

Jeden slot przetwarza dane z prędkością zależną od zapytania, ale w przybliżeniu:

  • Proste agregacje: ~0.5-1 TB/slot/godzina
  • Złożone JOINy: ~0.1-0.3 TB/slot/godzina

Orientacyjny próg:

  • Jeśli przetwarzasz <5 TB/miesiąc: on-demand jest tańszy (~$31/miesiąc)
  • Jeśli przetwarzasz 5-20 TB/miesiąc: są porównywalne - zależy od wzorca
  • Jeśli przetwarzasz >20 TB/miesiąc: sloty prawie zawsze są tańsze

Dla finansowych pipeline (przewidywalne zapytania, dzienne batch joby): sloty są zazwyczaj korzystniejsze od 10 TB/miesiąc wzwyż, bo zapytania są regularne i planowalne.

Konfiguracja autoscaling

-- Rezerwacja z autoscaling (Standard Edition)
-- Baseline: 100 slotów, max: 400 slotów
CREATE RESERVATION `project.region-europe-central2.prod_reservation`
OPTIONS (
  edition = 'STANDARD',
  slot_capacity = 100,
  autoscale_max_slots = 400
);

Płacisz za baseline 24/7, a dodatkowe sloty są doliczane per-sekundowo gdy pipeline potrzebuje więcej mocy.

 

Kontrola kosztów - budżety i alerty

Budżety w Cloud Billing

Ustaw budżety na poziomie projektu z alertami:

  • 50% budżetu: powiadomienie email (wcześnie ostrzeżenie)
  • 80% budżetu: alert Slack/PagerDuty (działanie wymagane)
  • 100% budżetu: alert krytyczny (eskalacja do menadżera)

Custom cost controls na BigQuery

-- Maksymalny koszt zapytania per-użytkownik (1 GB = ~$0.006)
-- Ustaw na 10 GB aby jedno zapytanie nie przekroczyło $0.06
ALTER PROJECT `my-project`
SET OPTIONS (
  default_query_job_timeout_ms = 300000,  -- 5 minut max
  maximum_bytes_billed = 10737418240      -- 10 GB max per zapytanie
);

Można też ustawić na poziomie zapytania:

SELECT account_id, SUM(amount)
FROM `project.dataset.transactions`
WHERE transaction_date = '2026-07-01'
GROUP BY account_id
OPTIONS (maximum_bytes_billed = 1073741824);  -- 1 GB max

Jeśli zapytanie potrzebuje większej skali - zakończy się błędem zamiast generować nieoczekiwany koszt.

 

Typowe błędy w finansowych pipeline

1. SELECT * w scheduled queries

Scheduled query, który raz dziennie wykonuje SELECT * na tabeli historycznej, generuje stały, wysoki koszt. Rozwiązanie: zawsze wybieraj konkretne kolumny i dodawaj filtr partycji.

2. JOIN na niepartycjonowanych tabelach tymczasowych

Wzorzec, który widzimy regularnie:

-- ZŁY wzorzec: JOIN na pełnej tabeli temp
WITH temp AS (SELECT * FROM big_table)
SELECT * FROM temp JOIN other_table ON ...

BigQuery materializuje temp jako tabelę tymczasową BEZ partycjonowania. JOIN skanuje ją w całości. Rozwiązanie: filtruj WEWNĄTRZ CTE.

3. Brak expire time na tabelach staging

Pipeline’y ETL tworzą tabele tymczasowe (_staging, _temp) i nie usuwają ich. Nie generują kosztów zapytań, ale generują koszty storage ($0.02/GB/miesiąc dla aktywnego storage).

-- Ustaw automatyczne wygaśnięcie na tabelach staging
ALTER TABLE `project.dataset.transactions_staging`
SET OPTIONS (expiration_timestamp = TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 7 DAY));

4. Widoki (VIEW) zamiast materialized views

Zwykły VIEW nie cache’uje wyniku - każde odpytanie wykonuje pełne zapytanie bazowe. Jeśli dashboard odpytuje VIEW 100 razy dziennie, płacisz 100x za ten sam skan. Materialized View rozwiązuje ten problem.

5. Streaming inserts gdzie wystarczy batch load

Streaming inserts kosztują $0.05/GB (oprócz storage). Dla finansowego pipeline, który ładuje dane raz dziennie (EOD batch), streaming nie ma sensu - batch load jest darmowy.

 

Monitoring kosztów BigQuery

INFORMATION_SCHEMA - analiza zużycia

-- Top 10 najdroższych zapytań w ostatnim tygodniu
SELECT
  user_email,
  query,
  total_bytes_processed / POW(1024, 4) AS tb_processed,
  total_bytes_processed / POW(1024, 4) * 6.25 AS estimated_cost_usd,
  creation_time
FROM `region-eu`.INFORMATION_SCHEMA.JOBS
WHERE creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
  AND job_type = 'QUERY'
  AND state = 'DONE'
ORDER BY total_bytes_processed DESC
LIMIT 10;
-- Koszty per-użytkownik w ostatnim miesiącu
SELECT
  user_email,
  COUNT(*) AS query_count,
  SUM(total_bytes_processed) / POW(1024, 4) AS total_tb,
  SUM(total_bytes_processed) / POW(1024, 4) * 6.25 AS total_cost_usd
FROM `region-eu`.INFORMATION_SCHEMA.JOBS
WHERE creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  AND job_type = 'QUERY'
GROUP BY user_email
ORDER BY total_cost_usd DESC;

Same te zapytania kosztują mało (skanują metadane, nie dane użytkowników).

 

Checklist optymalizacji BigQuery dla fintech

Natychmiastowe (dzień 1)

  • Włącz require_partition_filter na wszystkich dużych tabelach
  • Ustaw maximum_bytes_billed na 10 GB jako default projektu
  • Przejrzyj scheduled queries - usunięcie SELECT * i dodanie filtrów partycji
  • Skonfiguruj budżety i alerty w Cloud Billing

Krótkoterminowe (tydzień 1-2)

  • Dodaj partycjonowanie po dacie do tabel, które go nie mają
  • Dodaj clustering na kolumnach najczęściej używanych w WHERE
  • Stwórz materialized views dla powtarzalnych agregacji w panelach analitycznych
  • Ustaw expire time na tabelach staging/temp

Średnioterminowe (miesiąc 1-2)

  • Oceń próg opłacalności slotów vs on-demand
  • Wdróż BI Engine dla dashboardów Looker Studio
  • Skonfiguruj monitoring INFORMATION_SCHEMA (cotygodniowy raport kosztów)
  • Rozważ model showback per-zespół na podstawie zużycia BigQuery

 

Jak możemy pomóc

W Devopsity optymalizujemy infrastrukturę GCP dla polskich firm z sektora finansowego i fintech. Typowe zaangażowanie w optymalizację BigQuery:

  • Audyt istniejących tabel i zapytań (identyfikacja top-10 kosztowych zapytań) - 1 dzień
  • Implementacja partycjonowania, clustering i materialized views - 2-3 dni
  • Konfiguracja budżetów, alertów i monitoringu - 1 dzień
  • Analiza progu opłacalności slotów i migracja modelu cenowego - 1-2 dni

Jeśli Twoje rachunki za BigQuery rosną proporcjonalnie do liczby analityków zamiast do ilości danych - prawdopodobnie problem leży w strukturze tabel, nie w skali biznesu.

Jerzy Kopaczewski

Rachunki za BigQuery wymykają się spod kontroli?

Umów się na bezpłatną 30-minutową rozmowę. Bez sprzedaży - techniczna dyskusja o Twoich procesach danych.

 

Najczęściej zadawane pytania

Ile kosztuje BigQuery on-demand?

$6.25 za terabajt przetworzonych danych. Pierwszy terabajt miesięcznie jest darmowy (Free Tier). Storage kosztuje $0.02/GB/miesiąc (aktywne dane) lub $0.01/GB/miesiąc (dane niemodyfikowane >90 dni).

Czy partycjonowanie jest darmowe?

Tak. Partycjonowanie nie wprowadza dodatkowych kosztów - po prostu zmienia fizyczny układ danych. Oszczędności pojawiają się natychmiast, bo zapytania skanują mniej danych.

Sloty czy on-demand dla pipeline z 50 scheduled queries dziennie?

Zależy od wolumenu danych. Jeśli Twoje 50 zapytań łącznie skanuje >500 GB/dzień (>15 TB/miesiąc), sloty będą tańsze. Policz: 15 TB x $6.25 = $94/miesiąc on-demand vs 50 slotów Standard Edition = $0.04 x 50 x 730h = $1,460/miesiąc. W tym przypadku on-demand jest tańszy. Przy 100 TB/miesiąc ($625 on-demand) sloty zaczynają wygrywać.

Czy mogę ograniczyć budżet BigQuery per-zespół?

Tak. Użyj osobnych projektów GCP per-zespół z indywidualnymi budżetami Cloud Billing. Alternatywnie: BigQuery Reservations pozwalają przypisać sloty do konkretnych projektów, zapobiegając sytuacji, gdzie jeden zespół “zjada” zasoby innego.

Jak szybko zobaczę oszczędności po wdrożeniu partycjonowania?

Natychmiast - od pierwszego zapytania na partycjonowanej tabeli. Jeśli migrujesz istniejącą tabelę, musisz ją odtworzyć z partycjonowaniem (CTAS - CREATE TABLE AS SELECT) lub użyć bq cp z opcją time partitioning.

GCP BigQuery FinOps fintech data pipelines optymalizacja kosztów Google Cloud

Przeczytaj również:

Poprzedni post