Learning Platform
Глоссарий Troubleshooting
Урок 11.05 · 26 мин
Продвинутый
icebergsnowflakebigquerycatalogstuning

Iceberg в dbt и warehouse-specific tuning

В предыдущих уроках разобрали parsing, threads, selectors, microbatch — это уровень dbt. Сейчас спускаемся на уровень warehouse: Iceberg как открытый табличный формат, Snowflake/BigQuery specific tuning для dbt-jobs.

Это важно для двух причин:

  1. Iceberg становится de facto стандартом для cross-warehouse data (2025-2026 trend).
  2. Правильный warehouse setup может сократить cost dbt-jobs в 5-10x.
incremental_predicates: оптимизация MERGE и DELETE (dbt II)

Iceberg в контексте dbt

Apache Iceberg — открытый table format, который позволяет хранить данные в object storage (S3, GCS, Azure Blob) с транзакционными гарантиями и schema evolution. В 2025 году все major warehouses (Snowflake, BigQuery, Databricks) добавили нативную поддержку Iceberg.

Зачем это нужно для dbt:

  1. Cross-warehouse читаемость — таблица на Iceberg может читаться из Snowflake, Trino, Spark, DuckDB одновременно.
  2. No vendor lock-in — данные в S3, не в проприетарном Snowflake format.
  3. Cost — object storage в 10x дешевле warehouse storage.
  4. Time travel — Iceberg хранит snapshots, можно SELECT FROM table AS OF ‘2026-05-01’.

dbt поддерживает Iceberg через catalogs.yml (новый файл, появился в dbt-core 1.9).

catalogs.yml — структура

catalogs.yml лежит в корне dbt-проекта (рядом с dbt_project.yml). Определяет, какие external catalogs доступны:

# catalogs.yml
catalogs:
  - name: aws_glue
    active_write_integration: dev_iceberg
    write_integrations:
      - name: dev_iceberg
        catalog_type: glue
        external_volume: my_iceberg_storage
        adapter_properties:
          file_format: parquet
          table_type: iceberg

Поля:

  • name — логическое имя catalog’а, на которое модели ссылаются.
  • catalog_type — тип catalog (glue для AWS Glue, polaris для Snowflake Polaris, unity для Databricks Unity).
  • external_volume — Snowflake-объект для доступа к S3 (Snowflake-specific).
  • adapter_properties — adapter-specific параметры.

В моделях вы указываете catalog в config():

-- models/iceberg_events.sql
{{ config(
    materialized='table',
    catalog='aws_glue'
) }}

select
    event_id,
    event_timestamp,
    user_id
from {{ source('app', 'events') }}

dbt при run:

  1. Создаёт таблицу через Snowflake (или Iceberg-compatible warehouse).
  2. Файлы parquet кладутся в S3 (через external_volume).
  3. Metadata записывается в AWS Glue catalog.
  4. Таблица доступна через любой Iceberg-reader.

Partition pruning на Iceberg

Iceberg хранит partition metadata в catalog. При SELECT с фильтром по partition column — warehouse читает только нужные partition-файлы:

-- Запрос с filter
SELECT * FROM iceberg_events WHERE event_date = '2026-05-15'

Iceberg catalog говорит: “файлы за эту дату — vot эти 100 parquet’ов в S3”. Warehouse читает только их, не сканит весь dataset. Это partition pruning.

Сравнение с обычной таблицей в Snowflake:

ПодходСкан 1B-row tableCost (X-Large WH)
Snowflake native + cluster keys5 sec$0.01
Iceberg + partition pruning4 sec$0.005
Iceberg без partitioning60 sec$0.20
External Parquet без partition metadata120 sec$0.40

Iceberg даёт почти нативную производительность Snowflake, но в open format.

Конфигурация partition pruning в dbt

{{ config(
    materialized='incremental',
    catalog='aws_glue',
    partition_by={
        'field': 'event_timestamp',
        'data_type': 'timestamp',
        'granularity': 'day'
    },
    cluster_by=['user_id']
) }}

dbt при создании таблицы передаёт partition spec в Iceberg catalog. После этого все downstream queries автоматически используют partition pruning.

WARNING

Iceberg gotcha: после создания таблицы partition spec immutable (в Iceberg v1 spec). Если вы потом меняете partition_by в dbt-конфиге и делаете --full-refresh — таблица переезжает на новый spec. Без full-refresh — старая partition scheme.

Iceberg vs native Snowflake/BigQuery: trade-offs

Iceberg vs Native tables: trade-offs

Iceberg даёт portability и cost saving на storage. Native — лучшую performance и tooling integration.

IcebergApache Iceberg — open format. Файлы в S3/GCS/Azure Blob. Catalog metadata в Glue/Polaris/Unity. Читается из любого Iceberg-compatible engine
vs
NativeSnowflake/BigQuery proprietary format. Высокая производительность, нативная интеграция с warehouse features. Vendor lock-in, дорогое storage
Use case IcebergCross-team data sharing, ML feature stores (read by Spark + DuckDB), data lake architectures, cost-sensitive storage
Use case NativeHigh-performance BI queries, real-time aggregations, complex transactions, dbt models с heavy joins/aggs
dbt supportdbt 1.9+ через catalogs.yml. Поддерживается на dbt-snowflake 1.9+, dbt-databricks, dbt-bigquery (через BigLake)
dbt supportNative — везде и всегда, default. Никакой extra config

Реальная архитектура 2026:

  • Staging — native warehouse tables (быстрые fact-агрегации).
  • Intermediate/marts — native warehouse.
  • Exposable data (для других team / Spark ML) — Iceberg.

Через catalog: 'aws_glue' в конкретной модели — она становится Iceberg, остальные native. dbt поддерживает heterogeneous setup.

Snowflake-specific tuning для dbt jobs

Это самый частый stack в production. Конкретные рекомендации:

Warehouse size по типу job

# profiles.yml
production:
  outputs:
    prod:
      type: snowflake
      account: my-account
      warehouse: DBT_DEFAULT_WH  # для большинства моделей
      role: TRANSFORMER
      threads: 16

В моделях override через config():

-- Маленькие staging-модели
{{ config(snowflake_warehouse='DBT_STAGING_WH') }}  -- Small

-- Тяжёлые marts с aggregations
{{ config(snowflake_warehouse='DBT_MARTS_WH') }}    -- Large

-- Heavy ML feature engineering
{{ config(snowflake_warehouse='DBT_HEAVY_WH') }}    -- X-Large

Auto-suspend для cost

Snowflake warehouse биллится по времени running. Auto-suspend останавливает warehouse через N секунд после последнего query:

ALTER WAREHOUSE DBT_PROD_WH SET AUTO_SUSPEND = 60;  -- 1 минута

Default — 600 seconds (10 минут). После одного dbt-job warehouse продолжает крутиться 10 минут впустую. Setting на 60s экономит 90% idle cost.

Trade-off: при холодном старте warehouse есть 1-3 sec overhead. На каждом dbt run это +1-3s, не критично для часовых run-ов.

Multi-cluster warehouses

Для CI и concurrent runs:

CREATE WAREHOUSE DBT_CI_WH WITH
    WAREHOUSE_SIZE = 'MEDIUM'
    MIN_CLUSTER_COUNT = 1
    MAX_CLUSTER_COUNT = 4
    AUTO_SCALING_POLICY = 'STANDARD'
    AUTO_SUSPEND = 60;

Snowflake автоматически добавляет clusters при concurrent load. На CI с 10 одновременными PR-ами — кластеры масштабируются, каждый PR не ждёт.

Query tagging для observability

-- В dbt_project.yml
on-run-start: "ALTER SESSION SET QUERY_TAG = 'dbt_run|{{ invocation_id }}|{{ target.name }}'"

Теперь все queries dbt-runs тэгированы. В Snowflake Query History можно фильтровать:

SELECT
    QUERY_TEXT,
    EXECUTION_TIME,
    BYTES_SCANNED,
    CREDITS_USED_CLOUD_SERVICES
FROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY
WHERE QUERY_TAG LIKE 'dbt_run%'
ORDER BY START_TIME DESC;

Это даёт точную attribution cost per dbt run — какие модели сколько потратили.

Resource monitors

CREATE RESOURCE MONITOR DBT_PROD_MONITOR WITH
    CREDIT_QUOTA = 1000
    FREQUENCY = MONTHLY
    NOTIFY_USERS = ('data_engineer1', 'data_engineer2')
    TRIGGERS
        ON 75 PERCENT DO NOTIFY
        ON 90 PERCENT DO SUSPEND
        ON 100 PERCENT DO SUSPEND_IMMEDIATE;

Это страховка от cost explosion. Если dbt-job уходит в бесконечный loop из-за бага, warehouse автоматически suspended на 90% месячного бюджета.

BigQuery-specific tuning

BigQuery — другая модель: slots, не warehouses.

On-demand vs Flat-rate (reservations)

On-demand: pay-per-query (TB scanned).

  • $5 per TB scanned (US prices).
  • Concurrency limit 100 queries/project.
  • Хорошо для unpredictable workloads.

Flat-rate (reservations): pay-per-slot-hour.

  • Бронируете N slots, queries делят их.
  • Concurrency unlimited (но queries делят slots).
  • Хорошо для predictable workloads (dbt scheduled runs).

Для dbt в production обычно используется reservations + commit period 1 month:

# profiles.yml
production:
  outputs:
    prod:
      type: bigquery
      project: my-gcp-project
      dataset: analytics_prod
      threads: 24
      priority: batch  # batch priority cheaper than interactive

priority: batch — это важный параметр. Batch queries имеют lower priority (могут wait), но дешевле в reservation model. Для scheduled dbt-runs batch — natural choice.

Partition pruning

BigQuery аналогично Snowflake требует partition columns. В dbt:

{{ config(
    materialized='incremental',
    partition_by={
        'field': 'event_date',
        'data_type': 'date',
        'granularity': 'day'
    },
    cluster_by=['user_id', 'event_type']
) }}

Cluster keys в BigQuery — это secondary sort. Когда query filter включает cluster_by columns, BigQuery читает меньше partitions.

—use_legacy_sql и dialect

Современный BigQuery использует Standard SQL (default). Legacy SQL deprecated. dbt-bigquery всегда использует Standard. Просто избегайте dependencies на legacy syntax в макросах.

Table expiration

Для temp tables / staging:

{{ config(
    materialized='table',
    expiration_timestamp='TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)'
) }}

BigQuery автоматически удалит таблицу через 30 дней. Полезно для PR-temp schemas — после merge PR schema удаляется без manual cleanup.

DuckDB tuning

В контексте курса — DuckDB как обучающий warehouse. Production tuning тоже актуален для local dev / CI:

my_project:
  target: dev
  outputs:
    dev:
      type: duckdb
      path: './my_project.duckdb'
      threads: 4
      settings:
        memory_limit: '8GB'        # default — 80% RAM, обычно слишком много
        temp_directory: '/tmp/duckdb_spill'  # disk для spillover на больших aggs
        max_memory: '8GB'

memory_limit критичен — без него DuckDB ест ВСЁ memory, что замедляет систему (swap, OOM). Set explicit limit.

temp_directory — для spilling на больших aggregations. Без него — OOM. С — disk-based fallback (медленнее но не падает).

DuckDB extensions

extensions:
  - httpfs    # S3/HTTP reads
  - parquet   # Parquet files
  - json      # JSON parsing

Extensions — это native libraries, которые расширяют DuckDB. Для dbt с S3-sources нужны httpfs + parquet.

Comprehensive prod setup: пример

Объединённый пример для production-проекта на Snowflake с Iceberg:

# catalogs.yml
catalogs:
  - name: aws_glue_iceberg
    active_write_integration: prod
    write_integrations:
      - name: prod
        catalog_type: glue
        external_volume: s3_external_vol
        adapter_properties:
          file_format: parquet
          table_type: iceberg
# profiles.yml
production:
  target: prod
  outputs:
    prod:
      type: snowflake
      account: my-account
      user: dbt_runner_svc
      role: TRANSFORMER
      database: ANALYTICS
      schema: PROD
      warehouse: DBT_DEFAULT_WH
      threads: 16
      private_key_path: '/secrets/dbt_runner.p8'
-- dbt_project.yml
models:
  my_project:
    +on-run-start: "ALTER SESSION SET QUERY_TAG = 'dbt|{{ invocation_id }}'"

    staging:
      +materialized: view
      +snowflake_warehouse: DBT_STAGING_WH

    intermediate:
      +materialized: table
      +snowflake_warehouse: DBT_MARTS_WH

    marts:
      +materialized: table
      +snowflake_warehouse: DBT_MARTS_WH

    iceberg_exports:
      +catalog: aws_glue_iceberg
      +materialized: incremental
      +partition_by:
        field: event_date
        data_type: date
        granularity: day

С этим setup:

  • Staging — small warehouse, fast view rebuild.
  • Intermediate/marts — large warehouse, table materialization.
  • Iceberg exports — open format для downstream ML/sharing.
  • Query tagging — full cost attribution в Snowflake usage.

CI/CD tuning для cost

Для PR-ов на CI добавьте:

ci:
  outputs:
    ci:
      type: snowflake
      warehouse: DBT_CI_WH   # multi-cluster small
      schema: 'pr_{{ env_var("PR_NUMBER") }}'
      threads: 24

Schema per PR — это паттерн dynamic schemas. После merge PR schema удаляется (через scheduled cleanup job).

-- Cleanup script запускается раз в день
DROP SCHEMA IF EXISTS ANALYTICS.PR_123 CASCADE;

Это даёт isolated CI runs без data conflicts между PR-ами.

TIP

Real-world cost saving: команда из 20 разработчиков на Snowflake Medium warehouse без CI tuning тратит ~15K/мес.Сmulticluster+SlimCI+perPRschemas+autosuspend60s—стоимостьпадаетдо15K/мес. С multi-cluster + Slim CI + per-PR schemas + auto-suspend 60s — стоимость падает до 2-3K/мес. Это 80% saving на тех же запросах.

Performance benchmark на realistic project

Конкретные numbers с production-проекта на Snowflake + Iceberg:

OperationNative SnowflakeIcebergDifference
INSERT 100M rows45s90sIceberg 2x slower (file format overhead)
SELECT с partition filter5s6sAlmost same
Full scan 1B rows60s80sIceberg slower (S3 latency)
dbt —full-refresh 500GB table25 min35 minIceberg 40% slower
Storage cost (1TB/year)$25/mo (Snowflake)$3/mo (S3)Iceberg 8x cheaper

Iceberg slower на writes, но storage cost compensates. Для mostly-read datasets — Iceberg рекомендуется.

Проверка знанийKnowledge check
Команда планирует переход на Iceberg для нескольких таблиц-marts, которые читаются Spark ML pipeline (downstream). Lead инженер спрашивает у вас (senior dbt): "стоит ли весь проект перевести на Iceberg для consistency?" Что отвечаете?
ОтветAnswer
Нет, не стоит — это over-engineering. Реальный подход — **hybrid architecture**: native warehouse для большинства, Iceberg для specific use cases. Анализ: (1) **Cost-benefit per layer**: - Staging — высокий churn (rebuild часто), низкое storage usage. Native warehouse оптимизирован для частых writes. Iceberg здесь даёт extra file format overhead без выигрыша. - Intermediate — то же, fast rebuilds важнее storage cost. - Marts (BI) — высокий read, низкий churn. Native warehouse быстрее для BI queries (cluster keys, micro-partitions). Большинство BI users не получают пользы от Iceberg. - Marts (ML/cross-team) — это где Iceberg shines. Spark/DuckDB могут читать напрямую из S3, нет vendor lock-in. (2) **dbt support для hybrid**: catalogs.yml позволяет per-model выбор catalog. Можно иметь: - ANALYTICS.PROD.fct_orders — native Snowflake (для BI). - ICEBERG.PROD.fct_orders_export — Iceberg copy для ML/sharing. Через два materializations в одной модели или через downstream model export. (3) **Operational complexity**: Iceberg требует additional infrastructure: - AWS Glue catalog (или Snowflake Polaris, или Databricks Unity). - External volume в Snowflake (S3 access setup). - IAM permissions для read/write S3. - Iceberg metadata maintenance (snapshot expiration, compaction). Перевод всего проекта на Iceberg = эти всё на ВСЕ таблицы. Сложность × количество моделей. (4) **Performance trade-offs**: - Writes 1.5-2x медленнее на Iceberg vs native Snowflake. - Reads с partition filter — почти одинаковые. - Full scans — Iceberg 30-40% медленнее (S3 latency). - Если вы делаете 1000 dbt-runs/день — 2x slowdown на writes значит 2x cost для compute, что съест storage saving. (5) **Правильный план**: - Идентифицировать конкретные marts, которые consumed external Spark ML. 5-15% от всего проекта. - Перевести только их на Iceberg (через catalogs.yml). - Остальное оставить на native Snowflake. - Setup Glue catalog, IAM, external volume — настроить инфраструктуру. - Мониторить cost — storage saving может компенсировать write overhead, может нет, зависит от read/write ratio. (6) **Что сказать lead инженеру**: "Hybrid setup. Native для 85% моделей (производительность для BI). Iceberg для 15% downstream-consumed моделей (sharing). Это даёт нам portability там где нужно, без overhead везде где не нужно. Setup новой Iceberg-таблицы это PR на 20 строк yaml-конфига plus один-разовый infra setup." Это и есть senior decision-making — не "modern technology везде", а "right tool for the job per layer".

Резюме

  • Iceberg — open table format в S3/GCS. Cross-warehouse readable, cheap storage.
  • catalogs.yml — dbt 1.9+ конфиг для Iceberg/external catalogs.
  • Partition pruning на Iceberg работает аналогично native warehouse, но immutable spec после create.
  • Snowflake tuning: разные warehouses per layer, auto-suspend 60s, query tagging, resource monitors.
  • BigQuery tuning: reservations + batch priority, partition_by + cluster_by, table expiration для temp.
  • DuckDB tuning: memory_limit, temp_directory обязательны для production-like CI.
  • Hybrid architecture — Iceberg только для cross-system marts, native везде остальное.
  • Cost engineering: Slim CI + per-PR schemas + multi-cluster — экономит 80%+ от naive setup.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 6. Что такое catalogs.yml в dbt-проекте?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5