๋ฐ์ดํฐ ์จ์ดํ์ฐ์ค์ ๋ฐ์ดํฐ๋ฅผ ์๋ ๊ฒ๋ณด๋ค ์ด๋ ค์ด ๊ฒ์ ์์ธ ๋ฐ์ดํฐ๋ฅผ ์ ๋ขฐํ ์ ์๊ฒ ์ ์งํ๋ ๊ฒ์ด๋ค.
dbt๋ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ง๋ค์ด์ง ๋๊ตฌ์ด๋ค.
dbt๊ฐ ์๊ธด ์ด์
- dbt ์ด์ ์ ๋ฐ์ดํฐ ๋ณํ ์์
- SQL ํ์ผ์ด ์๋ฐฑ ๊ฐ๊ฐ ๋๋ฉด ๊ด๋ฆฌ๊ฐ ๋ถ๊ฐ๋ฅํด์ง๋ค.
- ์ด๋ค ์์๋ก ์คํํด์ผ ํ๋์ง ์ ์ ์๋ค.
- ๋๊ฐ ์ธ์ ์์ ํ๋์ง ์ถ์ ์ด ์๋๋ค.
- ํ ์คํธ๊ฐ ์์ด์ ๋ฐ์ดํฐ๊ฐ ๊นจ์ ธ๋ ํ์ฐธ ๋ค์ ์๊ฒ ๋๋ค.
- ๊ฐ์ ๋ก์ง์ ์ฌ๋ฌ ํ์ผ์์ ์ค๋ณต์ผ๋ก ์์ฑํ๋ค.
- SQL ํ์ผ์ด ์๋ฐฑ ๊ฐ๊ฐ ๋๋ฉด ๊ด๋ฆฌ๊ฐ ๋ถ๊ฐ๋ฅํด์ง๋ค.
transformation_v1.sql
transformation_v1_final.sql
transformation_v1_final_์ง์ง์ต์ข
.sql
transformation_v2_์์ .sql
- dbt๋ ์ด ๋ฌธ์ ๋ค์ ํ ๋ฒ์ ํด๊ฒฐํ๋ค.
ํต์ฌ ๊ฐ๋ 1 - ๋ ์ด์ด ๊ตฌ์กฐ
- dbt๋ SQL ํ์ผ์ ์ญํ ์ ๋ฐ๋ผ ์ธ ๋ ์ด์ด๋ก ๋๋ ์ ๊ด๋ฆฌํ๋ค.
models/
โโโ staging/ ← ์์ค ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋๋ก ์ฌ๋ฆฌ๋ ๋ ์ด์ด
โ โโโ stg_orders.sql
โ โโโ stg_customers.sql
โโโ intermediate/ ← ์ค๊ฐ ๋ณํ ๋ ์ด์ด
โ โโโ int_orders_with_customers.sql
โโโ marts/ ← ์ต์ข
๋ถ์์ฉ ๋ ์ด์ด (Star Schema)
โโโ fct_orders.sql
โโโ dim_customers.sql
- ๊ฐ ๋ ์ด์ด์ ์ญํ ์ ๋ช
ํํ๋ค.
- staging : ์์ค ์๋ณธ ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋๋ก ์ฌ๋ฆฌ๋, ์ปฌ๋ผ๋ช ๊ณผ ํ์ ๋ง ์ ๋ฆฌํ๋ค.
- intermediate : staging ๋ฐ์ดํฐ๋ฅผ ์กฐ์ธํ๊ฑฐ๋ ๊ฐ๊ณตํ๋ ์ค๊ฐ ๋จ๊ณ๋ค.
- marts : ๋ถ์๊ฐ๋ BI ๋๊ตฌ๊ฐ ์ง์ ์ฌ์ฉํ๋ ์ต์ข ํ ์ด๋ธ์ด๋ค.
ํต์ฌ ๊ฐ๋ 2 - ref()๋ก ์์กด์ฑ ์ ์ธ
- dbt์์ ํ ์ด๋ธ ๊ฐ ์ฐธ์กฐ๋ '{{ ref() }}'๋ก ์ ์ธํ๋ค.
-- marts/fct_orders.sql
SELECT
o.order_id,
o.customer_id,
o.amount,
c.region
FROM {{ ref('stg_orders') }} o
LEFT JOIN {{ ref('stg_customers') }} c
ON o.customer_id = c.customer_id
- {{ ref() }} ํ๋๋ก ๋ ๊ฐ์ง๊ฐ ํด๊ฒฐ๋๋ค.
- dbt๊ฐ ์๋์ผ๋ก ์คํ ์์๋ฅผ ๊ฒฐ์ ํ๋ค. (DAG ์์ฑ)
- 'stg_orders'๊ฐ ์๋ฃ๋์ง ์์ผ๋ฉด 'fct_orders'๋ ์คํ๋์ง ์๋๋ค.
ํต์ฌ ๊ฐ๋ 3 - ๋ฐ์ดํฐ ํ ์คํธ
- dbt test๋ ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์์ ๋ฐ์ดํฐ๊ฐ ๊นจ์ง ์ค ๋ชจ๋ฅด๊ณ ๋์๋ณด๋๊ฐ ๊ณ์ ๋์๊ฐ๋ ์ํฉ์ ๋ฐฉ์งํ๋ค.
1. Generic Test - ๋ด์ฅ ํ ์คํธ
- 'schema.yml'์ ์ ์ธ๋ง ํ๋ฉด ๋๋ค. SQL์ ์ง์ ์์ฑํ์ง ์์๋ ๋๋ค.
- dbt ๋ด์ฅ Generic Test๋ 4์ข : 'unique', 'not_null', 'accepted_values', 'relationships'
models:
- name: fct_orders
columns:
- name: order_id
tests:
- unique # ์ค๋ณต ํ ์์ด์ผ ํจ
- not_null # null ์์ด์ผ ํจ
- name: status
tests:
- accepted_values:
values: ['placed', 'shipped', 'delivered', 'cancelled']
- name: customer_id
tests:
- not_null
- relationships:
to: ref('dim_customers')
field: customer_id # FK ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ
2. Singular Test - ์ปค์คํ ํ ์คํธ
- ๋น์ฆ๋์ค ๋ก์ง์ ๋ง๋ ํ ์คํธ๋ SQL ํ์ผ๋ก ์ง์ ์์ฑํ๋ค.
- ํต์ฌ ์์น : ๊ฒฐ๊ณผ๊ฐ 0๊ฑด = ํต๊ณผ, 1๊ฑด ์ด์ = ์คํจ
- ๋ฌธ์ ๊ฐ ์๋ ๋ฐ์ดํฐ๋ฅผ ์ฐพ๋ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๊ฐ ์์ด์ผ ํ ์คํธ๋ฅผ ํต๊ณผํ๋ค.
-- tests/assert_revenue_is_positive.sql
-- ํ๋ถ ๊ฑด์ ์ ์ธํ ์ฃผ๋ฌธ์ revenue๋ ํญ์ ์์์ฌ์ผ ํ๋ค.
SELECT order_id
FROM {{ ref('fct_orders') }}
WHERE status != 'refunded'
AND revenue <= 0
ํ์ฅ ํจํค์ง - dbt-expectations
- ๋ ํ๋ถํ ํ ์คํธ๊ฐ ํ์ํ๋ฉด 'dbt-expectations' ํจํค์ง๋ฅผ ์ด๋ค.
- name: amount
tests:
- dbt_expectations.expect_column_values_to_be_between:
min_value: 0
max_value: 10000000
- name: ordered_at
tests:
- dbt_expectations.expect_column_values_to_be_of_type:
column_type: timestamp
ํ ์คํธ ์ฌ๊ฐ๋ ์ค์
- ๋ชจ๋ ํ
์คํธ ์คํจ๊ฐ ํ์ดํ๋ผ์ธ์ ๋ฉ์ถฐ์ผ ํ๋ ๊ฑด ์๋๋ค.
- ๋น์ฆ๋์ค ์ํฉํธ๊ฐ ํฐ ํ ์คํธ๋ 'error', ์ฐธ๊ณ ์ฉ์ 'warn'์ผ๋ก ๋๋ ์ ๊ด๋ฆฌํ๋ค.
- name: order_id
tests:
- unique:
severity: error # ์คํจ ์ ํ์ดํ๋ผ์ธ ์ค๋จ (๊ธฐ๋ณธ๊ฐ)
- not_null:
severity: warn # ์คํจํด๋ ๊ฒฝ๊ณ ๋ง, ํ์ดํ๋ผ์ธ์ ๊ณ์
๋ ์ด์ด๋ณ ํ ์คํธ ์ ๋ต
- ๋ ์ด์ด๊ฐ ์ฌ๋ผ๊ฐ์๋ก ํ
์คํธ๋ฅผ ๋ ์๊ฒฉํ๊ฒ ์ ์ฉํ๋ค.
- ์์ ๋ ์ด์ด๋ก ์ฌ๋ผ์ฌ์๋ก ์ด๋ฏธ ๊ฑธ๋ฌ์ง ๋ฐ์ดํฐ์ด๊ธฐ ๋๋ฌธ์ ์ต์ข Mart์์ ๋ฌธ์ ๊ฐ ๋ฐ๊ฒฌ๋๋ฉด ๊ทธ๋งํผ ๋ ์ฌ๊ฐํ ์ด์
staging ๋ ์ด์ด -> not_null, unique, accepted_values (๊ธฐ๋ณธ ๊ฒ์ฌ)
intermediate ๋ ์ด์ด -> relationships, ๋น์ฆ๋์ค ๋ฃฐ (๋ณํ ๋ก์ง ๊ฒ์ฌ)
marts ๋ ์ด์ด -> row count, ๊ฐ ๋ฒ์, ๋ ์ง ์ฐ์์ฑ (๊ฐ์ฅ ์๊ฒฉํ๊ฒ)
AirFlow์ ์ฐ๋
- ๋ชจ๋ธ ์คํ -> ํ ์คํธ -> ํต๊ณผํ๋ฉด ๋์๋ณด๋ ๊ฐฑ์ . ํ ์คํธ๊ฐ ์คํจํ๋ฉด ๊นจ์ง ๋ฐ์ดํฐ๊ฐ ๋์๋ณด๋์ ์ฌ๋ผ๊ฐ์ง ์๋๋ค.
run_dbt_models = BashOperator(
task_id = 'dbt_run',
bash_command = 'dbt run --select marts'
)
run_dbt_test = BashOperator(
task_id = 'dbt_test',
bash_command = 'dbt test --select marts'
)
load_to_dashboard = BigQueryOperator(...)
run_dbt_models >> run_dbt_tests >> load_to_dashboard
์ ์ฒด ๋ฐ์ดํฐ ํ๋ฆ์์ dbt์ ์์น
- ELT ๊ตฌ์กฐ์์ T(Transform)๋ฅผ ๋ด๋นํ๋ ๊ฒ์ด dbt.
- Airflow๊ฐ '์ธ์ , ์ด๋ค ์์๋ก ์คํํ ์ง'๋ฅผ ๊ฒฐ์ ํ๋ค๋ฉด, dbt๋ '๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ๋ณํํ ์ง'๋ฅผ ๋ด๋นํ๋ค.
[OLTP: MySQL / PostgreSQL]
↓
Airbyte / Fivetran ← Extract & Load
↓
[Raw ๋ฐ์ดํฐ: BigQuery]
↓
dbt ← Transform (์ฌ๊ธฐ๊ฐ dbt)
↓
[Marts: Star Schema]
↓
Looker / Tableau
'Database > Engineering' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [DE] ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ์ค๊ณ ์์น (2) | 2026.05.22 |
|---|---|
| [DE] ๋ฐฐ์น vs ์คํธ๋ฆฌ๋ฐ (2) | 2026.05.21 |
| [DE] ๋ฐ์ดํฐ์จ์ดํ์ฐ์ค ๋ชจ๋ธ๋ง ๊ธฐ๋ณธ - Star Schema (0) | 2026.05.20 |
| [DE] OLTP vs OLAP (2) | 2026.05.19 |