ํํธ 3: Testing, Documentation & Deployment ๐
Source: Dev.to
๋งคํฌ๋ก โ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ SQL ํจ์ ๐ง
๋งคํฌ๋ก๋ ํ์ด์ฌ์ ํจ์์ ๊ฐ์ต๋๋ค โ ํ ๋ฒ ์์ฑํ๋ฉด ์ด๋์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ฐ์ดํฐ ์์ง๋์ด๋ง ์ค์บ ํ
#dbt #AnalyticsEngineering #DataModeling
Source: โฆ
๋งคํฌ๋ก โ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ SQL ํจ์ ๐ง
๋งคํฌ๋ก ์์ด (์ค๋ณต ์ฝ๋)
-- โ Repeated everywhere
CASE
WHEN payment_type = 1 THEN 'Credit card'
WHEN payment_type = 2 THEN 'Cash'
WHEN payment_type = 3 THEN 'No charge'
WHEN payment_type = 4 THEN 'Dispute'
WHEN payment_type = 5 THEN 'Unknown'
ELSE 'Unknown'
END AS payment_type_description
๋งคํฌ๋ก์ ํจ๊ป (ํ ๋ฒ๋ง ์์ฑ)
-- macros/get_payment_type_description.sql
{% macro get_payment_type_description(payment_type) %}
CASE {{ payment_type }}
WHEN 1 THEN 'Credit card'
WHEN 2 THEN 'Cash'
WHEN 3 THEN 'No charge'
WHEN 4 THEN 'Dispute'
WHEN 5 THEN 'Unknown'
ELSE 'Unknown'
END
{% endmacro %}
๋ชจ๋ ๋ชจ๋ธ์์ ์ฌ์ฉํ๊ธฐ
-- models/staging/stg_green_tripdata.sql
SELECT
payment_type,
{{ get_payment_type_description('payment_type') }} AS payment_type_description
FROM {{ source('staging', 'green_tripdata') }}
dbt์ Jinja ๊ตฌ๋ฌธ
| ๊ตฌ๋ฌธ | ๋ชฉ์ | ์์ |
|---|---|---|
{{ }} | ํํ์ ์ถ๋ ฅ | {{ ref('my_model') }} |
{% %} | ๋ ผ๋ฆฌ / ์ ์ด ํ๋ฆ | {% if is_incremental() %} |
{# #} | ์ฃผ์ | {# This is a comment #} |
Packages โ ๋ค๋ฅธ ์ฌ๋์ด ๋ง๋ ๋งคํฌ๋ก์ ๋ชจ๋ธ ์ฌ์ฌ์ฉ
| Package | What it Does |
|---|---|
| dbt_utils | ์ผ๋ฐ์ ์ธ SQL ํฌํผ(๋๋ฆฌํค, ํผ๋ฒ ๋ฑ) |
| dbt_codegen | YAML ๋ฐ SQL ์๋ ์์ฑ |
| dbt_expectations | Great Expectations ์คํ์ผ ํ ์คํธ |
| dbt_audit_helper | ๋ฆฌํฉํฐ๋ง ์ ๋ชจ๋ธ ์ถ๋ ฅ ๋น๊ต |
Create packages.yml
packages:
- package: dbt-labs/dbt_utils
version: 1.1.1
Install packages
dbt deps
Use a macro from a package
-- Using dbt_utils to generate surrogate keys
SELECT
{{ dbt_utils.generate_surrogate_key(['vendorid', 'pickup_datetime']) }} AS trip_id,
*
FROM {{ source('staging', 'green_tripdata') }}
ํ ์คํธ โ ๋ฐ์ดํฐ๊ฐ ๊ธฐ๋์ ๋ถํฉํ๋์ง ํ์ธ
1๏ธโฃ ์ผ๋ฐ ํ ์คํธ (๊ฐ์ฅ ์ผ๋ฐ์ )
์คํค๋ง YAML ํ์ผ์ ์ถ๊ฐํฉ๋๋ค:
# models/staging/schema.yml
version: 2
models:
- name: stg_green_tripdata
columns:
- name: trip_id
tests:
- unique # No duplicate values
- not_null # No null values
- name: payment_type
tests:
- accepted_values:
values: [1, 2, 3, 4, 5, 6] # Allowed values only
- name: pickup_location_id
tests:
- relationships: # Referential integrity
to: ref('dim_zones')
field: location_id
| ํ ์คํธ | ์ค๋ช |
|---|---|
unique | ์ปฌ๋ผ์ ์ค๋ณต ๊ฐ์ด ์์ |
not_null | ์ปฌ๋ผ์ NULL ๊ฐ์ด ์์ |
accepted_values | ๊ฐ์ด ์ง์ ๋ ๋ชฉ๋ก์ ํฌํจ๋์ด์ผ ํจ |
relationships | ๊ฐ์ด ๋ค๋ฅธ ํ ์ด๋ธ์ ์กด์ฌํด์ผ ํจ |
2๏ธโฃ ๋จ์ผ(๋ง์ถค) ํ ์คํธ
tests/ ํด๋์ .sql ํ์ผ์ ๋ฐฐ์นํฉ๋๋ค:
-- tests/assert_positive_fare_amount.sql
-- Test FAILS if any rows are returned
SELECT
trip_id,
fare_amount
FROM {{ ref('fct_trips') }}
WHERE fare_amount < 0
๋ชจ๋ ํ์ ์ฌํ(๋
ธ๋์ ๋ฐ ์ด๋ก์)์ ํฌํจํ๋ ์ฌ์ค ํ
์ด๋ธ.
์ฌํ๋น ํ๋์ ํ์ ์๊ธ ์์ธ ๋ฐ ๊ตฌ์ญ ์ ๋ณด๊ฐ ํฌํจ๋ฉ๋๋ค.
Generate & serve docs:
dbt docs generate # Build the site
dbt docs serve # Open in a browser
์ฌ์ดํธ์ ํฌํจ๋๋ ๋ด์ฉ:
- ๋ชจ๋ธ ์ค๋ช
- ์ปฌ๋ผ ์ ์
- ์ข ์์ฑ ๊ทธ๋ํ (์๊ฐ์ DAG)
- ์์ค ์ ๋ณด
์ผ๋ฐ dbt ๋ช ๋ น
| ๋ช ๋ น | ์ํ ๋ด์ฉ |
|---|---|
dbt run | ๋ชจ๋ ๋ชจ๋ธ์ ๋น๋ (๋ทฐ/ํ ์ด๋ธ ์์ฑ) |
dbt test | ๋ชจ๋ ํ ์คํธ ์คํ |
dbt build | ๋ชจ๋ธ๊ณผ ํ ์คํธ๋ฅผ ํจ๊ป ์คํ (์ถ์ฒ) |
dbt compile | ์คํ ์์ด SQL ์์ฑ |
dbt debug | ์ฐ๊ฒฐ ๋ฐ ํ๋ก์ ํธ ์ค์ ํ์ธ |
dbt seed | ์๋ CSV ํ์ผ ๋ก๋ |
dbt deps | ํจํค์ง ์ค์น |
dbt docs generate | ๋ฌธ์ ์์ฑ |
dbt docs serve | ๋ก์ปฌ์์ ๋ฌธ์ ์ ๊ณต |
dbt retry | ์คํจํ ๋ชจ๋ธ ์ฌ์๋ |
ํน์ ๋ชจ๋ธ ์ ํ
# ๋จ์ผ ๋ชจ๋ธ
dbt run --select stg_green_tripdata
# ๋ชจ๋ธ + ๋ชจ๋ ์์ ์ข
์์ฑ
dbt run --select +fct_trips
# ๋ชจ๋ธ + ๋ชจ๋ ํ์ ๋ชจ๋ธ
dbt run --select stg_green_tripdata+
# ์๋ฐฉํฅ
dbt run --select +fct_trips+
# ํด๋ ๋ด ๋ชจ๋ ๋ชจ๋ธ
dbt run --select staging.*
# ์ฌ๋ฌ ๋ชจ๋ธ
dbt run --select stg_green_tripdata stg_yellow_tripdata
# ๊ฐ๋ฐ (๊ธฐ๋ณธ ๋์)
dbt run
# ํ๋ก๋์
๋์
dbt run --target prod
Materializations โ dbt๊ฐ ๋ชจ๋ธ์ ์ ์ฅํ๋ ๋ฐฉ์
| ์ ํ | ์์ฑ๋๋ ๊ฒ | ์ผ๋ฐ์ ์ธ ์ฌ์ฉ ์ฌ๋ก |
|---|---|---|
view | SQL ๋ทฐ (์ฟผ๋ฆฌ๊ฐ ์ ์ฅ๋๊ณ ์ ๊ทผ ์ ์คํ) | ์คํ ์ด์ง ๋ชจ๋ธ, ์์ฃผ ๋ณ๊ฒฝ๋๋ ๋ก์ง |
table | ๋ฌผ๋ฆฌ ํ ์ด๋ธ (๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋จ) | ์ต์ข ๋งํธ, ๋๊ท๋ชจ ๋ฐ์ดํฐ์ , ์ฑ๋ฅ์ด ์ค์ํ ์ฟผ๋ฆฌ |
incremental | ์๋ก์ด ๋ฐ์ดํฐ๋ง ์ถ๊ฐ | ๋งค์ฐ ํฐ ํ ์ด๋ธ, ์ด๋ฒคํธํ ๋ฐ์ดํฐ |
ephemeral | ์์ฑ๋์ง ์์ (๋ค์ด์คํธ๋ฆผ์์ CTE) | ํฌํผ ๋ชจ๋ธ, ์ค๊ฐ ๋จ๊ณ |
๋ชจ๋ธ ํ์ผ์์ materialization ์ค์ ํ๊ธฐ
{{ config(materialized='table') }}
SELECT *
FROM {{ ref('stg_trips') }}
๋๋ dbt_project.yml ์ ์ฒด์ ์ ์ฉํ๊ธฐ
models:
my_project:
staging:
materialized: view
marts:
materialized: table
๋น ๋ฅธ ๊ฒฐ์ ๋์ฐ๋ฏธ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Should I use a view or a table? โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๊ธฐ์ ๋ก์ง์ด ์์ฃผ ๋ณ๊ฒฝ๋๊ฑฐ๋ ๋ฐ์ดํฐ์
์ด ์ถฉ๋ถํ ์์ ๊ฐ ์ฟผ๋ฆฌ๋ง๋ค ์ฌ๊ณ์ฐํ๋ ๋น์ฉ์ด ์ ๋ ดํ ๋ ๋ทฐ๋ฅผ ์ฌ์ฉํ์ธ์.
์ฑ๋ฅ, ํ์ ์๋น๋ฅผ ์ํ ์ง์์ ์ธ ๋ฐ์ดํฐ๊ฐ ํ์ํ๊ฑฐ๋ ๋ฐ์ดํฐ์
์ด ํฌ๊ณ ์ฌ๊ณ์ฐ ๋น์ฉ์ด ๋ง์ด ๋ค ๋ ํ
์ด๋ธ์ ์ฌ์ฉํ์ธ์.
Decision Flow
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Is the query expensive? โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
Yes No
โ โ
โผ โผ
โโโโโโโโโโโ โโโโโโโโโโโ
โ TABLE โ โ VIEW โ
โโโโโโโโโโโ โโโโโโโโโโโ
Use VIEW when:
- Staging models (simple transformations) โ ์คํ ์ด์ง ๋ชจ๋ธ(๊ฐ๋จํ ๋ณํ)
- Logic changes frequently โ ๋ก์ง์ด ์์ฃผ ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ
- Storage cost is a concern โ ์คํ ๋ฆฌ์ง ๋น์ฉ์ด ์ฐ๋ ค๋๋ ๊ฒฝ์ฐ
Use TABLE when:
- Final marts are queried often โ ์ต์ข ๋งํธ๊ฐ ์์ฃผ ์กฐํ๋๋ ๊ฒฝ์ฐ
- Complex joins / aggregations โ ๋ณต์กํ ์กฐ์ธ/์ง๊ณ
- Query performance matters โ ์ฟผ๋ฆฌ ์ฑ๋ฅ์ด ์ค์ํ ๊ฒฝ์ฐ
ํ๋ก์ ํธ ๊ฐ์ โ NYC ํ์ ๋ฐ์ดํฐ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ RAW DATA โ
โ green_tripdata (GCS/BigQuery) โ yellow_tripdata (GCS/BigQuery)โ
โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโ
โ โ
โผ โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ STAGING LAYER โ
โ stg_green_tripdata โ stg_yellow_tripdata โ
โ (cleaned, renamed) โ (cleaned, renamed) โ
โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโ
โ โ
โโโโโโโโโโโโฌโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ INTERMEDIATE LAYER โ
โ int_trips_unioned โ
โ (green + yellow combined) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ MARTS LAYER โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ dim_zones โ โ fct_trips โ โ fct_monthly_zone_rev โ โ
โ โ (dimension)โ โ (fact) โ โ (report) โ โ
โ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
๋ชจ๋ธ ์นดํ๋ก๊ทธ
| ๋ชจ๋ธ | ์ ํ | ์ค๋ช |
|---|---|---|
stg_green_tripdata | Staging | ์ ์ ๋ ๊ทธ๋ฆฐ ํ์ ๋ฐ์ดํฐ |
stg_yellow_tripdata | Staging | ์ ์ ๋ ์๋ก์ฐ ํ์ ๋ฐ์ดํฐ |
int_trips_unioned | Intermediate | ์๋ก์ฐโฏ+โฏ๊ทธ๋ฆฐ ์ฌํ ๊ฒฐํฉ |
dim_zones | Dimension | ๊ตฌ์ญ ์กฐํ ํ ์ด๋ธ |
fct_trips | Fact | ์ฌํ๋น ํ ํ |
fct_monthly_zone_revenue | Report | ๊ตฌ์ญ๋ณ ์๋ณ ์์ต |
๋ก์ปฌ ๊ฐ๋ฐ (DuckDB)
์ฅ์ : ๋ฌด๋ฃ, ํด๋ผ์ฐ๋ ๊ณ์ ํ์ ์์
๋จ์ : ๋จธ์ ์ ๋ฆฌ์์ค๋ก ์ ํ๋จ
# 1. Install dbt with the DuckDB adapter
pip install dbt-duckdb
# 2. Clone the project
git clone https://github.com/DataTalksClub/data-engineering-zoomcamp
cd data-engineering-zoomcamp/04-analytics-engineering/taxi_rides_ny
# 3. Create `profiles.yml` in `~/.dbt/`
# 4. Test the connection
dbt debug
# 5. Build the project
dbt build --target prod
ํด๋ผ์ฐ๋ ๊ฐ๋ฐ (dbt Cloudโฏ+โฏBigQuery)
Pros: ๊ฐ๋ ฅํจ, ํ ํ์
, ์ค์ผ์ค๋ฌ
Cons: GCP ๊ณ์ ์ด ํ์ํฉ๋๋ค (๋ฌด๋ฃ ํฐ์ด ์ด์ฉ ๊ฐ๋ฅ)
- dbt Cloud ๊ณ์ ์ ์์ฑํ์ธ์ (๋ฌด๋ฃ).
- ์ด๋ฅผ BigQuery ํ๋ก์ ํธ์ ์ฐ๊ฒฐํฉ๋๋ค.
- dbt Cloud IDE์์ ๋ ํฌ์งํ ๋ฆฌ๋ฅผ ๋ณต์ ํฉ๋๋ค.
- ๋ค์ ๋ช ๋ น์ ์คํํฉ๋๋ค:
dbt build --target prod
์ผ๋ฐ์ ์ธ ๋ฌธ์ ํด๊ฒฐ ๐
โProfile not foundโ
dbt_project.yml์ ์๋profile์ด๋ฆ์ดprofiles.yml์ ์๋ ์ด๋ฆ๊ณผ ์ผ์นํ๋์ง ํ์ธํ์ธ์.profiles.yml์ด~/.dbt/์ ์์นํ๋์ง ํ์ธํ์ธ์.
โSource not foundโ
sources.yml์ ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค/์คํค๋ง ์ด๋ฆ์ ํ์ธํ์ธ์.- ๋ฐ์ดํฐ๊ฐ ์จ์ดํ์ฐ์ค์ ๋ก๋๋์๋์ง ํ์ธํ์ธ์.
ref()ํธ์ถ์ ์คํ๊ฐ ์๋์ง ํ์ธํ๊ณ , ์ฐธ์กฐ๋ ๋ชจ๋ธ์ด ์กด์ฌํ๋์ง ํ์ธํ์ธ์.
์ต์ ๋ฉ๋ชจ๋ฆฌ ์กฐ์ (profiles.yml):
settings:
memory_limit: '2GB'
ํต์ฌ ๊ฐ๋
- Analytics Engineering์ ๋ฐ์ดํฐ ์์ง๋์ด๋ง๊ณผ ๋ฐ์ดํฐ ๋ถ์์ ์ฐ๊ฒฐํฉ๋๋ค.
- dbt๋ SQL ๋ณํ์ ์ํํธ์จ์ดโ์์ง๋์ด๋ง ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋์ ํฉ๋๋ค.
- Dimensional modeling์ ๋ฐ์ดํฐ๋ฅผ facts(์ด๋ฒคํธ)์ dimensions(์์ฑ)์ผ๋ก ์กฐ์งํฉ๋๋ค.
- ์ธ ๊ณ์ธต: staging(์์ ๋ณต์ฌ), intermediate(๋ณํ), marts(์ต์ข ์๋น์ฉ ํ ์ด๋ธ).
ref()์source()๋ ๋ชจ๋ธ ์์กด์ฑ์ ๊ตฌ์ถํ๋ ์ฃผ์ ํจ์์ ๋๋ค.- Testing์ ๋ฐ์ดํฐ ํ์ง์ ๋ณด์ฅํฉ๋๋ค โ
unique,not_null,accepted_values,relationships๋ฅผ ์ฌ์ฉํฉ๋๋ค. - ๋ฌธ์๋ YAML ์ค๋ช ์ผ๋ก๋ถํฐ ์๋ ์์ฑ๋ฉ๋๋ค.
dbt build๋ ์์กด์ฑ ์์๋๋ก ๋ชจ๋ ๊ฒ์ ์คํํ๊ณ ํ ์คํธํฉ๋๋ค.
์ถ๊ฐ ์๋ฃ ๐
- dbt ๋ฌธ์
- dbt ๊ธฐ๋ณธ ๊ณผ์ (๋ฌด๋ฃ)
- ์๋์ฐ ํจ์์ ๋ํ SQL ๋ณต์ต
- dbt ์ปค๋ฎค๋ํฐ Slack
ํ๋ณตํ ๋ชจ๋ธ๋ง! ๐