Cerințe preliminare și instalare

dbt Core necesită Python 3.8+ și se instalează prin pip. Important este să instalați nu numai pachetul de bază, ci șiadaptor specific pentru depozitul dvs. Fiecare depozit are propriul adaptor, deoarece dialectele SQL diferă.

# Installa dbt Core con l'adapter per PostgreSQL (ottimo per iniziare in locale)
pip install dbt-postgres

# Per BigQuery
pip install dbt-bigquery

# Per Snowflake
pip install dbt-snowflake

# Per DuckDB (ideale per sviluppo locale senza infrastruttura)
pip install dbt-duckdb

# Verifica l'installazione
dbt --version
# Core:
#   - installed: 1.9.0
#   - latest:    1.9.0 - Up to date!

Începeți cu DuckDB pentru dezvoltare locală

Dacă nu aveți acces imediat la BigQuery sau Snowflake, DuckDB este calea mai rapid de început: este o bază de date încorporată care rulează direct local, nu necesită infrastructură și dbt-duckdb funcționează pe orice mașină. Perfect pentru invatare fara costuri.

Creați primul proiect dbt

Comanda dbt init creează structura de foldere a unui proiect dbt și vă ghidează în configurația inițială:

dbt init jaffle_shop

# dbt chiederà:
# 1. Quale database vuoi usare? (postgres/bigquery/snowflake/...)
# 2. [Per postgres] host, port, user, password, database, schema

# La struttura creata:
jaffle_shop/
├── dbt_project.yml          # configurazione principale
├── README.md
├── analyses/               # query ad hoc (non materializzate)
├── macros/                 # funzioni Jinja riutilizzabili
├── models/
│   └── example/            # modelli di esempio (da eliminare)
├── seeds/                  # CSV statici
├── snapshots/              # snapshot per SCD
└── tests/                  # test SQL singolari

Fișierul dbt_project.yml

Inima configurației proiectului este dbt_project.yml. Definiți aici numele proiectului, versiunea dbt, căile de director și configurația globală dintre modele:

# dbt_project.yml
name: 'jaffle_shop'
version: '1.0.0'

# Versione minima di dbt richiesta
require-dbt-version: ">=1.8.0"

# Percorso del profile da usare (in profiles.yml)
profile: 'jaffle_shop'

# Directory dei modelli
model-paths: ["models"]
analysis-paths: ["analyses"]
test-paths: ["tests"]
seed-paths: ["seeds"]
macro-paths: ["macros"]
snapshot-paths: ["snapshots"]

# Dove salvare i log e i target compilati
target-path: "target"
log-path: "logs"
clean-targets: ["target", "dbt_packages"]

# Configurazione dei modelli per directory
models:
  jaffle_shop:
    # Tutti i modelli del progetto sono view per default
    +materialized: view

    staging:
      # I modelli in staging/ sono sempre view
      +materialized: view
      +schema: staging          # savedano in schema 'staging'

    marts:
      +materialized: table      # I marts sono table per performance
      +schema: marts

Fișierul profiles.yml

Acreditările de conectare intră ~/.dbt/profiles.yml (în directorul principal, nu în depozit). Fiecare profil poate avea mai multe ținte (dezvoltare, montaj, producție):

# ~/.dbt/profiles.yml
jaffle_shop:
  target: dev                    # target di default

  outputs:
    dev:
      type: postgres
      host: localhost
      port: 5432
      user: "{{ env_var('DB_USER') }}"      # usa variabili d'ambiente
      password: "{{ env_var('DB_PASSWORD') }}"
      dbname: jaffle_shop_dev
      schema: dbt_dev_federico   # schema personale per sviluppo
      threads: 4

    prod:
      type: postgres
      host: "{{ env_var('PROD_DB_HOST') }}"
      port: 5432
      user: "{{ env_var('PROD_DB_USER') }}"
      password: "{{ env_var('PROD_DB_PASSWORD') }}"
      dbname: jaffle_shop_prod
      schema: dbt_prod
      threads: 8

Convenția este că fiecare dezvoltator are un model personal (de ex. dbt_dev_federico) pentru a evita conflictele în timpul dezvoltării paralele.

Modele dbt: Unitatea fundamentală

Un model dbt este un fișier .sql în director models/. Conținutul este un simplu SELECT — dbt se ocupă de crearea vizualizării sau a tabelului corespunzător în depozit.

Să începem cu un exemplu realist. Să presupunem că avem o masă raw.orders in depozit cu date brute din aplicație:

-- models/staging/stg_orders.sql
-- Staging model: rinomina, casta, pulisce — nessuna logica di business

WITH source AS (
    SELECT * FROM {{ source('raw', 'orders') }}   -- 'source' punta alla sorgente raw
),

renamed AS (
    SELECT
        id                                         AS order_id,
        user_id                                    AS customer_id,
        order_date                                 AS created_at,
        status,
        CAST(amount AS DECIMAL(10,2))              AS total_amount,
        LOWER(payment_method)                      AS payment_method,
        _loaded_at                                 AS loaded_at    -- metadata pipeline
    FROM source
    WHERE id IS NOT NULL                           -- filtra record corrotti
)

SELECT * FROM renamed

Macro-ul ref().

Macro-ul ref() este cea mai importantă caracteristică a dbt. Când scrii {{ ref('stg_orders') }}, dbt:

  1. Rezolvă numele corect al tabelului/vizualizării din depozit pentru mediul curent
  2. Înregistrați dependența în graficul aciclic direcționat (DAG)
  3. Se asigură că modelul dependent rulează primul
-- models/marts/finance/orders_monthly.sql
-- Usa ref() per dipendere da stg_orders

WITH orders AS (
    SELECT * FROM {{ ref('stg_orders') }}          -- dbt risolve automaticamente lo schema
),

monthly_aggregated AS (
    SELECT
        DATE_TRUNC('month', created_at)            AS month,
        payment_method,
        COUNT(*)                                   AS order_count,
        SUM(total_amount)                          AS gross_revenue,
        AVG(total_amount)                          AS avg_order_value,
        COUNT(DISTINCT customer_id)                AS unique_customers
    FROM orders
    WHERE status = 'completed'
    GROUP BY 1, 2
)

SELECT * FROM monthly_aggregated

Macro-ul sursă ().

Pentru a accesa surse brute (tabele care nu sunt create de dbt), utilizați source() în loc de ref(). Sursele trebuie declarate într-un dosar sources.yml:

# models/staging/sources.yml
version: 2

sources:
  - name: raw                    # nome del source group
    database: raw_db             # database nel warehouse
    schema: public               # schema nel warehouse
    tables:
      - name: orders
        description: "Ordini grezzi dall'applicazione"
        loaded_at_field: _loaded_at    # campo per freshness check
        freshness:
          warn_after: {count: 12, period: hour}
          error_after: {count: 24, period: hour}
      - name: customers
        description: "Clienti grezzi dall'applicazione"

Cu această configurare, puteți rula dbt source freshness pentru a verifica asta sursele sunt actualizate înainte de începerea transformărilor.

Rulați dbt: comenzile de bază

# Esegui tutti i modelli (materialization nel warehouse)
dbt run

# Esegui solo i modelli staging
dbt run --select staging

# Esegui un singolo modello e tutte le sue dipendenze (+)
dbt run --select +orders_monthly

# Esegui tutti i test definiti nello schema YAML
dbt test

# Testa solo un modello specifico
dbt test --select stg_orders

# Compila i modelli senza eseguirli (utile per debug)
dbt compile

# Verifica freshness delle sorgenti
dbt source freshness

# Genera e serve la documentazione
dbt docs generate
dbt docs serve                  # apre http://localhost:8080

Structura șablonului recomandată

Structura pe trei niveluri recomandată de comunitatea dbt:

models/
├── staging/                    # Layer 1: vicino alla sorgente
│   ├── sources.yml            # dichiarazione sorgenti
│   ├── schema.yml             # test + documentazione
│   ├── stg_orders.sql
│   ├── stg_customers.sql
│   └── stg_products.sql
├── intermediate/               # Layer 2: join complessi (opzionale)
│   ├── int_orders_enriched.sql # join ordini + clienti
└── marts/                      # Layer 3: pronti per consumo
    ├── finance/
    │   ├── schema.yml
    │   ├── orders_monthly.sql
    │   └── revenue_by_country.sql
    └── marketing/
        └── customer_cohorts.sql

Anti-pattern: logica de afaceri în punere în scenă

Șabloanele de punere în scenă trebuie să facă doar operațiuni „prostie”: redenumiți coloanele, tipurile de difuzare, deduplicat. Logica de business (calcule, agregari, uniuni) intra in modelele intermediare sau magazine. Dacă modelul dvs. de pregătire are un GROUP BY sau mai mult de câteva coloane calculate, probabil că faci prea multe în acel strat.

Verificarea setării cu dbt debug

Înainte de a alerga dbt run, verificați dacă conexiunea depozitului funcționează:

dbt debug

# Output atteso:
# Configuration:
#   profiles.yml file [OK found and valid]
#   dbt_project.yml file [OK found and valid]
# Required dependencies:
#  - git [OK found]
# Connection:
#   host: localhost
#   port: 5432
#   user: federico
#   database: jaffle_shop_dev
#   schema: dbt_dev_federico
#   [OK connection ok]

Concluzii și pașii următori

Am configurat un proiect dbt funcțional cu structura pe trei niveluri (staging → intermediar → mart), profilele de conectare pentru diferite medii, sursele declarate cu verificarea prospetimei si primele modele cu ref() e source().

Următorul pas este să facem SQL-ul nostru dinamic cu Jinja: variabile, bucle, condiții și macrocomenzi reutilizabile care elimină duplicarea codului în depozit.