dbt 2026 ์๋ฒฝ ๊ฐ์ด๋: ๋ฐ์ดํฐ ๋ณํ, ํ ์คํธ ์ ๋ต, ๋ฉด์ ์ง๋ฌธ ์ด์ ๋ฆฌ
dbt๋ฅผ ํ์ฉํ ๋ฐ์ดํฐ ๋ณํ์ ํต์ฌ ๊ฐ๋ ๋ถํฐ ์ค๋ฌด๊น์ง, ๋ ์ด์ด๋ ๋ชจ๋ธ๋ง, ์ธํฌ๋ฆฌ๋ฉํ ์ ๋ต, ํ ์คํธ ๋ฐฉ๋ฒ๋ก , ๊ทธ๋ฆฌ๊ณ 2026๋ ๋ฐ์ดํฐ ์์ง๋์ด๋ง ๋ฉด์ ์์ ์์ฃผ ์ถ์ ๋๋ ์ง๋ฌธ์ ์ฝ๋ ์์ ์ ํจ๊ป ์์ธํ ๋ค๋ฃน๋๋ค.

dbt(data build tool)๋ ๋ชจ๋ ๋ฐ์ดํฐ ์จ์ดํ์ฐ์ค ๋ด์์ ๋ฐ์ดํฐ ๋ณํ์ ์ํํ๋ ํ์ค ํ๋ ์์ํฌ๋ก ์๋ฆฌ ์ก์์ผ๋ฉฐ, 2026๋ ํ์ฌ 40,000๊ฐ ์ด์์ ๊ธฐ์ ์ด ํ๋ก๋์ ํ๊ฒฝ์์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ์ด ํํ ๋ฆฌ์ผ์์๋ dbt ๋ฐ์ดํฐ ๋ณํ์ ํต์ฌ ๋ฉ์ปค๋์ฆ, ํ ์คํธ ์ ๋ต, ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ ์์ง๋์ด๋ง ๋ฉด์ ์์ ์ค์ ๋ก ์ถ์ ๋๋ ์ง๋ฌธ๋ค์ ์ฝ๋ ์์ ์ ํจ๊ป ์ดํด๋ด ๋๋ค.
dbt๋ ELT์์ T(Transform)๋ฅผ ๋ด๋นํ๋ ๋๊ตฌ์ ๋๋ค. SQL SELECT ๋ฌธ์ DDL(CREATE TABLE, CREATE VIEW, MERGE)๋ก ์ปดํ์ผํ์ฌ Snowflake, BigQuery, Redshift, Databricks ๋ฑ์ ์จ์ดํ์ฐ์ค์์ ์คํํฉ๋๋ค. ๋ฒ์ ๊ด๋ฆฌ, ์์กด์ฑ ํด๊ฒฐ, ํ ์คํธ, ๋ฌธ์ํ ๊ธฐ๋ฅ์ด ๊ธฐ๋ณธ์ผ๋ก ๋ด์ฅ๋์ด ์์ต๋๋ค.
๋ ์ด์ด๋ ๋ชจ๋ธ๋ง: Staging, Intermediate, Marts
์ ๊ตฌ์กฐํ๋ dbt ํ๋ก์ ํธ๋ ๋ณํ ์ฒ๋ฆฌ๋ฅผ ์ธ ๊ฐ์ ๋ ์ด์ด๋ก ๋ถ๋ฆฌํฉ๋๋ค. dbt ์ปค๋ฎค๋ํฐ์์ ๋๋ฆฌ ์ฑํ๋ ์ด ์ ๊ทผ๋ฒ์ ๊ฐ ๋ชจ๋ธ์ ๋จ์ผ ์ฑ ์์ ๋ณด์ฅํ๊ณ ๋๋ฒ๊น ์ ์ฉ์ดํ๊ฒ ํฉ๋๋ค.
Staging ๋ชจ๋ธ์ ์์ ๋ฐ์ดํฐ์ ๊ฐ์ฅ ๊ฐ๊น์ด ๋ ์ด์ด์ ์์นํฉ๋๋ค. ์ปฌ๋ผ๋ช ๋ณ๊ฒฝ, ํ์ ์บ์คํ , ๋ถํ์ํ ํ ํํฐ๋ง์ด ์ฃผ๋ ์ญํ ์ด๋ฉฐ, ์กฐ์ธ์ด๋ ์ง๊ณ๋ ์ํํ์ง ์์ต๋๋ค.
-- models/staging/stg_orders.sql
WITH source AS (
SELECT * FROM {{ source('ecommerce', 'raw_orders') }}
)
SELECT
id AS order_id,
customer_id,
CAST(order_date AS DATE) AS order_date,
CAST(amount AS DECIMAL(10, 2)) AS order_amount,
LOWER(status) AS order_status
FROM source
WHERE id IS NOT NULLIntermediate ๋ชจ๋ธ์ ๋น์ฆ๋์ค ๋ก์ง์ ์ ์ฉํ๋ ๋ ์ด์ด์
๋๋ค. ์กฐ์ธ, ์ง๊ณ, ์๋์ฐ ํจ์ ๋ฑ์ ํ์ฉํ๋ฉฐ, ref()๋ฅผ ํตํด Staging ๋ชจ๋ธ์ ์ฐธ์กฐํจ์ผ๋ก์จ DAG์ ์์กด์ฑ์ ๋ฑ๋กํฉ๋๋ค.
-- models/intermediate/int_customer_orders.sql
WITH orders AS (
SELECT * FROM {{ ref('stg_orders') }}
),
customers AS (
SELECT * FROM {{ ref('stg_customers') }}
)
SELECT
c.customer_id,
c.customer_name,
COUNT(o.order_id) AS total_orders,
SUM(o.order_amount) AS lifetime_value,
MIN(o.order_date) AS first_order_date,
MAX(o.order_date) AS last_order_date
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_nameMarts๋ ์ต์ข ์๋น ๋ ์ด์ด๋ก, ๋์๋ณด๋์ ๋ถ์๊ฐ๊ฐ ์ง์ ์ฟผ๋ฆฌํ๋ ์ ๋ฆฌ๋๊ณ ๋ฌธ์ํ๋ ํ ์ด๋ธ์ ์ ๊ณตํฉ๋๋ค.
์ด ๋ ์ด์ด ๊ตฌ์กฐ ๋๋ถ์ ์์ค์ ์ฅ์ ๊ฐ ๋ฐ์ํด๋ Staging ๋ ์ด์ด์๋ง ์ํฅ์ ๋ฏธ์น๋ฉฐ, ์ ์ฒด ํ์ดํ๋ผ์ธ์ผ๋ก ํ์ฐ๋์ง ์์ต๋๋ค. ๊ฐ ๋ ์ด์ด๋ ๋ ๋ฆฝ์ ์ผ๋ก ํ ์คํธํ ์ ์์ต๋๋ค.
ref() ํจ์์ DAG ์์กด์ฑ ํด๊ฒฐ
ref()๋ ๋จ์ํ ๋ณ์นญ์ด ์๋๋๋ค. {{ ref('stg_orders') }}๋ฅผ ํธ์ถํ๋ฉด ์ปดํ์ผ ์์ ์ ์ ๊ทํ๋ ํ
์ด๋ธ๋ช
์ด ํด๊ฒฐ๋จ๊ณผ ๋์์, dbt์ DAG(๋ฐฉํฅ ๋น์ํ ๊ทธ๋ํ)์ ์์กด์ฑ ์ฃ์ง๊ฐ ๋ฑ๋ก๋ฉ๋๋ค. ref()๊ฐ ์์ผ๋ฉด dbt๋ ์คํ ์์๋ฅผ ๊ฒฐ์ ํ ์ ์์ต๋๋ค.
ํํ ์ ์ง๋ฅด๋ ์ค์๋ ref() ๋์ ํ
์ด๋ธ๋ช
์ ์ง์ ํ๋์ฝ๋ฉํ๋ ๊ฒ์
๋๋ค. ์ด๋ ์์กด์ฑ ์ถ์ ์ ๊นจ๋จ๋ฆฌ๊ณ , ์์ ์์กด ๋ชจ๋ธ์ด ์ค๋น๋๊ธฐ ์ ์ ํ์ ๋ชจ๋ธ์ด ์คํ๋ ์ ์์ต๋๋ค.
-- ์๋ชป๋ ์: ํ๋์ฝ๋ฉ๋ ์ฐธ์กฐ, ์์กด์ฑ ์ถ์ ๋ถ๊ฐ
SELECT * FROM analytics.stg_orders
-- ์ฌ๋ฐ๋ฅธ ์: ref()๋ก ์์กด์ฑ ๋ฑ๋ก
SELECT * FROM {{ ref('stg_orders') }}DAG๋ dbt run --select stg_orders+์ ๊ฐ์ ๊ธฐ๋ฅ๋ ์ง์ํฉ๋๋ค. ์ด ๋ช
๋ น์ ์ง์ ๋ ๋ชจ๋ธ๊ณผ ๊ทธ ํ์์ ๋ชจ๋ ๋ชจ๋ธ์ ์คํํ๋ฉฐ, ์์ค ์คํค๋ง ๋ณ๊ฒฝ ํ ๋์์ ์ง์ ํ ์ฌ๋น๋์ ์ ์ฉํฉ๋๋ค.
๋งคํฐ๋ฆฌ์ผ๋ผ์ด์ ์ด์ : ์ ํฉํ ์คํ ๋ฆฌ์ง ์ ๋ต ์ ํ
dbt๋ ๋ค ๊ฐ์ง ๊ธฐ๋ณธ ๋งคํฐ๋ฆฌ์ผ๋ผ์ด์ ์ด์ ์ ์ ๊ณตํ๋ฉฐ, ์ ๊ทผ ํจํด๊ณผ ๋ฐ์ดํฐ ๊ท๋ชจ์ ๋ฐ๋ผ ์ ์ ํ ์ ํํด์ผ ํฉ๋๋ค.
| ๋งคํฐ๋ฆฌ์ผ๋ผ์ด์ ์ด์ | ์คํ ๋ฆฌ์ง | ์ ํฉํ ์ฉ๋ | ํธ๋ ์ด๋์คํ |
|---|---|---|---|
view | ์คํ ๋ฆฌ์ง ์์(์ฝ๊ธฐ ์ ์ฐ์ฐ) | ๊ฐ๋ฒผ์ด ๋ณํ, ์๊ท๋ชจ ๋ฐ์ดํฐ | ๋์ฉ๋ ๋ฐ์ดํฐ์์ ์ฝ๊ธฐ ์๋ ์ ํ |
table | ๋งค ์คํ๋ง๋ค ์ ์ฒด ํ ์ด๋ธ ์ฌ๊ตฌ์ถ | Mart ๋ ์ด์ด, ๋น ๋ฅธ ์ฝ๊ธฐ | ์ ์ฒด ์ฌ๊ตฌ์ถ, ๋์ ๋น์ฉ |
incremental | ์ ๊ท ํ๋ง ์ถ๊ฐ/๋ณํฉ | ๋๊ท๋ชจ ํฉํธ ํ ์ด๋ธ, ์ด๋ฒคํธ ์คํธ๋ฆผ | ๋ณต์กํ ๋ก์ง, unique_key ํ์ |
ephemeral | CTE๋ก ์ธ๋ผ์ธํ, ์ค์ฒดํํ์ง ์์ | ๋ชจ๋ธ ๊ฐ ๊ณต์ ๋๋ ์ฌ์ฌ์ฉ ๋ก์ง | ์ง์ ์ฟผ๋ฆฌ ๋ถ๊ฐ |
๊ธฐ๋ณธ๊ฐ์ view์
๋๋ค. ๋ชจ๋ธ์ config ๋ธ๋ก ๋๋ dbt_project.yml์์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
-- models/marts/fct_daily_revenue.sql
{{
config(
materialized='incremental',
unique_key='revenue_date',
incremental_strategy='merge'
)
}}
SELECT
DATE(order_date) AS revenue_date,
SUM(order_amount) AS daily_revenue,
COUNT(DISTINCT customer_id) AS unique_customers
FROM {{ ref('stg_orders') }}
WHERE order_status = 'completed'
{% if is_incremental() %}
AND order_date > (SELECT MAX(revenue_date) FROM {{ this }})
{% endif %}
GROUP BY DATE(order_date)is_incremental() ๋ธ๋ก์ ์ธํฌ๋ฆฌ๋ฉํ ๋น๋ ์์๋ง ์คํ๋ฉ๋๋ค. ์ ์ฒด ๋ฆฌํ๋ ์(dbt run --full-refresh) ์์๋ ๊ฑด๋๋ฐ์ด์ง๊ณ ํ
์ด๋ธ ์ ์ฒด๊ฐ ์ฌ๊ตฌ์ถ๋ฉ๋๋ค.
Data Engineering ๋ฉด์ ์ค๋น๊ฐ ๋์ จ๋์?
์ธํฐ๋ํฐ๋ธ ์๋ฎฌ๋ ์ดํฐ, flashcards, ๊ธฐ์ ํ ์คํธ๋ก ์ฐ์ตํ์ธ์.
๊ฐ ๋ ์ด์ด๋ณ ๋ฐ์ดํฐ ํ์ง ํ ์คํธ
dbt๋ ๋ ๊ฐ์ง ์ ํ์ ํ ์คํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. YAML์์ ์ ์ธํ๋ ์ ๋ค๋ฆญ ํ ์คํธ์, ์คํจ ์ ํ์ ๋ฐํํ๋ ๋ ๋ฆฝ SQL ํ์ผ๋ก ์์ฑํ๋ ์ฑ๊ทค๋ฌ ํ ์คํธ์ ๋๋ค.
์ ๋ค๋ฆญ ํ ์คํธ๋ ๊ตฌ์กฐ์ ์ ์ฝ ์กฐ๊ฑด์ ๊ฒ์ฆํฉ๋๋ค.
# models/staging/_stg_models.yml
version: 2
models:
- name: stg_orders
columns:
- name: order_id
tests:
- unique # ์ฃผ๋ฌธ ID ์ค๋ณต ์์
- not_null # ๋ชจ๋ ํ์ ์ฃผ๋ฌธ ID ์กด์ฌ
- name: order_status
tests:
- accepted_values:
values: ['completed', 'pending', 'cancelled', 'refunded']
- name: customer_id
tests:
- not_null
- relationships: # ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ
to: ref('stg_customers')
field: customer_id์ฑ๊ทค๋ฌ ํ ์คํธ๋ ์ ๋ค๋ฆญ ํ ์คํธ๋ก ํํํ ์ ์๋ ๋น์ฆ๋์ค ๊ท์น์ ๊ฒ์ฆํฉ๋๋ค.
-- tests/assert_revenue_never_negative.sql
-- ์ผ์ผ ์์ต์ด ์์์ธ ํ์ ๋ฐํํฉ๋๋ค(0ํ์ด ๊ธฐ๋๊ฐ)
SELECT
revenue_date,
daily_revenue
FROM {{ ref('fct_daily_revenue') }}
WHERE daily_revenue < 0์ ๋ ํ ์คํธ๋ dbt 1.8์์ ๋์ ๋ ๊ธฐ๋ฅ์ผ๋ก, ํต์ ๋ ์ ๋ ฅ๊ณผ ๊ธฐ๋ ์ถ๋ ฅ์ผ๋ก ๋ณํ ๋ก์ง์ ๊ฒ์ฆํฉ๋๋ค. ์จ์ดํ์ฐ์ค ์ฐ๊ฒฐ์ด ํ์ ์์ผ๋ฉฐ dbt ํ ์คํธ ๋จ๊ณ์์ ์ง์ ์คํ๋ฉ๋๋ค.
ํ
์คํธ ์ ๋ต์ ๋ฐ์ดํฐ ํ๋ฆ์ ๋ฐ๋ผ ๊ตฌ์ฑํด์ผ ํฉ๋๋ค. ์์ค ๋ ๋ฒจ์ ์ ์ ๋ ๊ฒ์ฌ์ ํ ์ ๊ฒ์ฆ, Staging ๋ ๋ฒจ์ ์คํค๋ง ํ
์คํธ(not_null, unique), Intermediate ๋ ๋ฒจ์ ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ, Mart ๋ ๋ฒจ์ ๋น์ฆ๋์ค ๋ก์ง ์ด์์
์์๋ก ์ ์ฉํ๋ ๊ฒ์ด ๊ถ์ฅ๋ฉ๋๋ค.
dbt Core v1.10๊ณผ Fusion ์์ง
dbt Core v1.10์์๋ run ๋ฐ build ๋ช
๋ น์ --sample ํ๋๊ทธ๊ฐ ๋์
๋์์ต๋๋ค. ์ด ํ๋๊ทธ๋ ref()์ source()์ ์๊ฐ ๊ธฐ๋ฐ ์ํ๋ง์ ์ ์ฉํ์ฌ, ์ ์ฒด ๋น๋ ๋น์ฉ ์์ด ๋ฐ์ดํฐ์ ์ผ๋ถ๋ถ์ผ๋ก ๋ณํ์ ๊ฒ์ฆํ ์ ์๊ฒ ํฉ๋๋ค. ์์ญ์ต ํ์ ํฉํธ ํ
์ด๋ธ์ ๋ค๋ฃจ๋ ๋ชจ๋ธ์ ๊ฐ๋ฐ ๋ฐ๋ณต ์์
์ ๋งค์ฐ ์ ์ฉํฉ๋๋ค.
dbt Fusion ์์ง์ Rust๋ก ์ฒ์๋ถํฐ ์ฌ๊ตฌ์ถ๋ ์์ง์ผ๋ก, dbt Cloud์ Snowflake, BigQuery, Redshift, Databricks ํ๊ฒฝ์์ ์ ๊ท ํ๋ก์ ํธ์ ๊ธฐ๋ณธ ์์ง์ด ๋์์ต๋๋ค. Fusion์ ์๋งจํฑ ๋ฒ์ ๋(2.0๋ถํฐ ์์)์ ๋์ ํ๊ณ , ์ปดํ์ผ๊ณผ ์คํ ์์ชฝ์์ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์์ผฐ์ต๋๋ค.
2026๋ ์ ๊ธฐํ ์ฃผ๋ชฉํ ๋งํ ์ ๋ฐ์ดํธ๋ก๋ ์ค์ ์ง์ค์ ๋ฉํธ๋ฆญ ์ ์๋ฅผ ์ํ Semantic Layer YAML ๋ช ์ธ, ๋ชจ๋ธ๋ณ ์จ์ดํ์ฐ์ค ์ปดํจํ ๋น์ฉ์ ์ถ์ ํ๋ Cost Insights(๋ฒ ํ), ๊ทธ๋ฆฌ๊ณ ์ ์ ์ถ์๋ ๋ค์ดํฐ๋ธ ํ๋ผ์ด๋น ํจํค์ง๊ฐ ์์ต๋๋ค.
๋งคํฌ๋ก์ Jinja๋ฅผ ํ์ฉํ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋ก์ง
๋์ผํ SQL ํจํด์ด ์ฌ๋ฌ ๋ชจ๋ธ์์ ๋ฐ๋ณต๋ ๊ฒฝ์ฐ, ๋งคํฌ๋ก๋ก ์ถ์ถํ๋ ๊ฒ์ด ์ ์ ํฉ๋๋ค. ๋งคํฌ๋ก๋ macros/ ๋๋ ํ ๋ฆฌ์ ์ ์ฅ๋๋ Jinja ํจ์์
๋๋ค.
-- macros/cents_to_dollars.sql
{% macro cents_to_dollars(column_name) %}
ROUND(CAST({{ column_name }} AS DECIMAL(10, 4)) / 100, 2)
{% endmacro %}๋ชจ๋ ๋ชจ๋ธ์์ ํธ์ถํ ์ ์์ต๋๋ค.
-- models/staging/stg_payments.sql
SELECT
payment_id,
order_id,
{{ cents_to_dollars('amount_cents') }} AS amount_dollars,
payment_method
FROM {{ source('stripe', 'payments') }}์ด๋ฅผ ํตํด ์ฝ๋๋ฒ ์ด์ค์ DRY ์์น์ ์ ์งํ ์ ์์ต๋๋ค. ๋ณํ ๊ณต์์ ํ์ํ ๋ชจ๋ ๋ชจ๋ธ์ ๋ณต์ฌํ๋ ๋์์ ์ ์ง๋ณด์ ๋น์ฉ ์ฆ๊ฐ์ ๋ถ์ผ์น์ ์์ธ์ด ๋ฉ๋๋ค.
๋ฐ์ดํฐ ์์ง๋์ด๋ง ๋ฉด์ ์์ ์ค์ ๋ก ์ถ์ ๋๋ ์ง๋ฌธ
2026๋ ๋ฐ์ดํฐ ์์ง๋์ด๋ง ๋ฉด์ ์์๋ ๊ธฐ์ด ์ง์์ ๋์ด์ dbt ์ดํด๋๋ฅผ ํ๊ฐํ๋ ์ถ์ธ์ ๋๋ค. ๋ค์์ ๋ชจ๋ ๋ฐ์ดํฐ ์คํ์ ํ์ฉํ๋ ๊ธฐ์ ์ ์ฑ์ฉ ํจํด์์ ์ถ์ถํ, ์ง์์๋ฅผ ์ฐจ๋ณํํ๋ ํต์ฌ ์ง๋ฌธ๋ค์ ๋๋ค.
Q: ์ธํฌ๋ฆฌ๋ฉํ ๋ชจ๋ธ์ด ์ผ๊ฐ์ ์ ์ฒด ํ ์ด๋ธ์ ์ฌ์ฒ๋ฆฌํ์ต๋๋ค. ์์ธ์ ๋ฌด์์ธ๊ฐ์?
๊ฐ์ฅ ํํ ์์ธ์ unique_key ์ปฌ๋ผ์ NULL ๊ฐ์ด ํฌํจ๋ ๊ฒฝ์ฐ์
๋๋ค. dbt๊ฐ NULL ํค๋ก MERGE๋ฅผ ์คํํ๋ฉด ๋ชจ๋ ํ์์ ๋งค์นญ์ด ์คํจํ์ฌ ์ค๋ณต ์ฝ์
์ด ๋ฐ์ํฉ๋๋ค. ๋ ๋ฒ์งธ ์์ธ์ dbt run --full-refresh๊ฐ ์๋์น ์๊ฒ ์คํ๋ ๊ฒฝ์ฐ์
๋๋ค. ์ด ๋ช
๋ น์ ํ
์ด๋ธ์ ์ฒ์๋ถํฐ ์ฌ๊ตฌ์ถํฉ๋๋ค. ์ธ ๋ฒ์งธ ์์ธ์ is_incremental() ํํฐ๊ฐ ํ๊ฒ ํ
์ด๋ธ์ ์์ง ์กด์ฌํ์ง ์๋ ์ปฌ๋ผ์ ์ฐธ์กฐํ๋ ๊ฒฝ์ฐ(์ฒซ ์คํ๊ณผ ์ดํ ์คํ์ ๋์ ์ฐจ์ด)์
๋๋ค. ๋๋ฒ๊น
์ target/compiled/ ๋๋ ํ ๋ฆฌ์ ์ปดํ์ผ๋ SQL ํ์ธ๋ถํฐ ์์ํฉ๋๋ค.
Q: ํ๋ก๋์ dbt ํ๋ก์ ํธ์์ ํ ์คํธ๋ฅผ ์ด๋ป๊ฒ ๊ณ์ธตํํด์ผ ํ๋์?
์์ค ์ ์ ๋ ๊ฒ์ฌ๊ฐ ๊ฐ์ฅ ๋จผ์ ์คํ๋์ด์ผ ํฉ๋๋ค. ์์ค๊ฐ ์
๋ฐ์ดํธ๋์ง ์์๋ค๋ฉด ํ์ ๋ชจ๋ธ์ ์ค๋๋ ๋ฐ์ดํฐ๋ก ์คํ๋์ด์๋ ์ ๋ฉ๋๋ค. Staging ํ
์คํธ์์๋ ์คํค๋ง ์ ์ฝ ์กฐ๊ฑด(๊ธฐ๋ณธ ํค์ unique + not_null, ํ์ฉ๊ฐ, ํ์
์บ์คํ
)์ ๊ฒ์ฆํฉ๋๋ค. Intermediate ํ
์คํธ์์๋ ์กฐ์ธ ๊ฐ ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ์ ํ์ธํฉ๋๋ค. Mart ํ
์คํธ์์๋ ๋น์ฆ๋์ค ๋ถ๋ณ ์กฐ๊ฑด(์์ต >= 0, ํ์ฑ ์ฌ์ฉ์ ์ >= ์ ๋ฃ ์ฌ์ฉ์ ์, ๋ถ๋ถ์ ํฉ = ์ ์ฒด)์ ์ด์ํธํฉ๋๋ค. ๋ชจ๋ ํ
์คํธ๋ PR ์์ ์ dev ์คํค๋ง์ ๋ํด CI์์ ์คํํ๊ณ , ๋ฐฐํฌ ํ์๋ ํ๋ก๋์
ํ๊ฒฝ์์ ์๋ฆผ๊ณผ ํจ๊ป ์ฌ์คํํฉ๋๋ค.
Q: ๋ชจ๋ธ์ ephemeral๋ก ํด์ผ ํ ๋์ view๋ก ํด์ผ ํ ๋์ ๊ธฐ์ค์ ๋ฌด์์ธ๊ฐ์?
ephemeral ๋ชจ๋ธ์ SQL์ CTE๋ก ์๋น ๋ชจ๋ธ์ ์ธ๋ผ์ธํํฉ๋๋ค. ๋ ๋ฆฝ์ ์ผ๋ก ์ฟผ๋ฆฌํ ํ์๊ฐ ์๋ ์ฌ์ฌ์ฉ ๋ก์ง์ ์ ํฉํฉ๋๋ค. view๋ ์ฝ๊ธฐ ์์ ์ ์ฐ์ฐ๋๋ฉฐ ์ฟผ๋ฆฌ ๊ฐ๋ฅํ ์ค๋ธ์ ํธ๋ก ์กด์ฌํฉ๋๋ค. ํธ๋ ์ด๋์คํ๋ก, ephemeral ๋ชจ๋ธ์ ์ง์ ํ ์คํธํ ์ ์๊ณ (์ด์์ ์ ์คํํ ํ ์ด๋ธ์ด ์กด์ฌํ์ง ์์), ๋ฐ์ดํฐ ๋ฆฌ๋์ง ๋๊ตฌ์๋ ํ์๋์ง ์์ต๋๋ค. ๋ด๋ถ ํฌํผ ๋ก์ง์๋ ephemeral์, ๋ ๋ฆฝ์ ์ธ ํ ์คํธ๋ ๋ชจ๋ํฐ๋ง์ด ํ์ํ ๊ฒฝ์ฐ์๋ view๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Q: source()์ ref()์ ์ฐจ์ด๋ฅผ ์ค๋ช
ํด ์ฃผ์ธ์.
source()๋ sources.yml ํ์ผ์ ์ ์๋ ์์ ํ
์ด๋ธ์ ๊ฐ๋ฆฌํต๋๋ค. ์ด ํ
์ด๋ธ๋ค์ dbt๊ฐ ๊ด๋ฆฌํ์ง ์๋ ๋์์
๋๋ค. ref()๋ ๋ค๋ฅธ dbt ๋ชจ๋ธ์ ๊ฐ๋ฆฌํต๋๋ค. ๋ ํจ์ ๋ชจ๋ DAG ์์กด์ฑ์ ๋ฑ๋กํ์ง๋ง, source()๋ ์ ์ ๋ ๊ฒ์ฌ(dbt source freshness)๋ ํ์ฑํํ๋ค๋ ์ ์ด ref()์์ ์ฐจ์ด์
๋๋ค. ์์ ํ
์ด๋ธ์๋ source()๋ฅผ, ๊ทธ ์ธ์๋ ref()๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ ํ์ด ์๋ ํ์์ด๋ฉฐ, dbt๊ฐ ๊ด๋ฆฌ ๋์๊ณผ ๋น๊ด๋ฆฌ ๋์์ ๊ตฌ๋ถํ๋ ๋ฐฉ์์
๋๋ค.
๋ ๋์ ๋ฒ์์ ๋ฐ์ดํฐ ์์ง๋์ด๋ง ๋ฉด์ ์ง๋ฌธ์ ETL vs ELT ํ์ดํ๋ผ์ธ ์ํคํ ์ฒ ๋ฑ์ ์ฃผ์ ๋ฅผ ํฌํจํ์ฌ, SharpSkill์ dbt ๊ธฐ์ด์ dbt ๊ณ ๊ธ ํจํด ์ธํฐ๋ํฐ๋ธ ์ฐ์ต ๋ชจ๋์์ ์ฒด๊ณ์ ์ผ๋ก ํ์ตํ ์ ์์ต๋๋ค.
์ฐ์ต์ ์์ํ์ธ์!
๋ฉด์ ์๋ฎฌ๋ ์ดํฐ์ ๊ธฐ์ ํ ์คํธ๋ก ์ง์์ ํ ์คํธํ์ธ์.
๊ฒฐ๋ก
- dbt๋ SQL SELECT ๋ฌธ์ DDL๋ก ์๋ ์ปดํ์ผํ์ฌ ์จ์ดํ์ฐ์ค ๋ด ์์ ๋ฐ์ดํฐ๋ฅผ ๋ณํํฉ๋๋ค. Staging/Intermediate/Mart์ ๋ ์ด์ด ๊ตฌ์กฐ๋ฅผ ํตํด ๊ฐ ๋ชจ๋ธ์ ๋จ์ผ ์ฑ ์์ ์ง์คํ ์ ์์ต๋๋ค
ref()ํจ์๋ ์์กด์ฑ ๊ด๋ฆฌ์ ํต์ฌ์ผ๋ก, ํ ์ด๋ธ๋ช ํด๊ฒฐ๊ณผ DAG ๊ตฌ์ถ์ ํตํ ์คํ ์์ ์ ์ด๋ฅผ ๋ด๋นํฉ๋๋ค- ์ธํฌ๋ฆฌ๋ฉํ ๋งคํฐ๋ฆฌ์ผ๋ผ์ด์ ์ด์
์ ๋๊ท๋ชจ ํ
์ด๋ธ์ ๋น์ฉ์ ์ ๊ฐํ์ง๋ง,
unique_key, NULL ๊ฐ,is_incremental()ํํฐ์ ์ธ์ฌํ ์ฒ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค - ํ ์คํธ๋ ๋ฐ์ดํฐ ํ๋ฆ์ ๋ฐ๋ผ ๊ตฌ์ฑํฉ๋๋ค. ์์ค ์ ์ ๋ ๊ฒ์ฌ, Staging์ ์คํค๋ง ์ ์ฝ, Intermediate์ ์ฐธ์กฐ ๋ฌด๊ฒฐ์ฑ, Mart์ ๋น์ฆ๋์ค ๋ก์ง ์ด์์ ์์๊ฐ ๊ถ์ฅ๋ฉ๋๋ค
- dbt Core v1.10์ ๋น ๋ฅธ ๋ฐ๋ณต ์์
์ ์ํ
--sampleํ๋๊ทธ๋ฅผ ๋์ ํ์ผ๋ฉฐ, Fusion ์์ง(Rust ๊ธฐ๋ฐ, ๋ฒ์ 2.0)์ด dbt Cloud์ ๊ธฐ๋ณธ ์์ง์ด ๋์์ต๋๋ค - dbt ๊ด๋ จ ๋ฉด์ ์ง๋ฌธ์ ์ ์ ์๊ธฐ๊ฐ ์๋ ์ค์ ์ฅ์ ๋๋ฒ๊น (์ธํฌ๋ฆฌ๋ฉํ ์ฌ์ฒ๋ฆฌ, NULL ํค, ์ค๋๋ ์์ค)์ ์ด์ ์ ๋ง์ถ๊ณ ์์ต๋๋ค. ์ปดํ์ผ๋ SQL๊ณผ CI ํ์ดํ๋ผ์ธ์ ๋ํ ์ค๋ฌด ๊ฒฝํ์ด ์๊ธฐ๋ ๋ต๋ณ๋ณด๋ค ์ค์ํฉ๋๋ค
์ฐ์ต์ ์์ํ์ธ์!
๋ฉด์ ์๋ฎฌ๋ ์ดํฐ์ ๊ธฐ์ ํ ์คํธ๋ก ์ง์์ ํ ์คํธํ์ธ์.
Data Engineering ์ฝ๋์ ๋ฒ๊ทธ๋ฅผ ์ฐพ์ ์ ์๋์
์ค์ ์ฝ๋ ํ ์กฐ๊ฐ, ์จ์ ๋ฒ๊ทธ ํ๋, ํ๋ฃจ ํ ๋ฒ. ๊ณ์ ์์ด ๋ฐ๋ก ๋์ ํ ์ ์์ต๋๋ค.

์์ฑ์
Anthony Fillion-MailletSharpSkill ์ฐฝ์ ์
10๋ ์ด์ ํ์คํ ๊ฐ๋ฐ์ ํด์์ต๋๋ค. SharpSkill์ ์ด์ํ๋ฉฐ ์ด๊ณณ์ ๊ฒ์๋๋ ๋ชจ๋ ๋ด์ฉ์ ์ฑ ์์ ์ง๋๋ค.
2026๋ 5์ 25์ผ ์ ๋ฐ์ดํธ
ํ๊ทธ
๊ณต์
๊ด๋ จ ๊ธฐ์ฌ

2026๋ ๋ฐ์ดํฐ ์์ง๋์ด๋ง ๋ฉด์ ์ง๋ฌธ ์์ 25๊ฐ
2026๋ ๋ฐ์ดํฐ ์์ง๋์ด๋ง ๋ฉด์ ์์ ๊ฐ์ฅ ๋ง์ด ์ถ์ ๋๋ 25๊ฐ์ง ํต์ฌ ์ง๋ฌธ๊ณผ ์ค๋ฌด ์ค์ฌ์ ๋ต๋ณ์ ์ ๊ณตํฉ๋๋ค.

2026๋ Apache Spark 4 ์๋ฒฝ ๊ฐ์ด๋: ์ ๊ท ๊ธฐ๋ฅ, Structured Streaming, ๋ฉด์ ์ง๋ฌธ
Apache Spark 4์ ํต์ฌ ์ ๊ท ๊ธฐ๋ฅ์ธ ANSI SQL ๋ชจ๋, VARIANT ๋ฐ์ดํฐ ํ์ , ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ ๋ชจ๋, Spark Connect๋ฅผ ์ฌ์ธต ๋ถ์ํฉ๋๋ค. ๋ฐ์ดํฐ ์์ง๋์ด๋ง ๋ฉด์ ์ ์ํ ํ์ ์ง๋ฌธ๊ณผ ๋ต๋ณ๋ ํจ๊ป ์ ๊ณตํฉ๋๋ค.

2026 ETL vs ELT ์๋ฒฝ ๋น๊ต: ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ์ํคํ ์ฒ ์ค๊ณ ๊ฐ์ด๋
2026๋ ETL๊ณผ ELT์ ํต์ฌ ์ฐจ์ด์ , ๋น์ฉ ๋ถ์, ๊ตฌํ ํจํด์ ์์ธํ ๋น๊ตํฉ๋๋ค. dbt, Airflow๋ฅผ ํ์ฉํ ์ค์ ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ์ค๊ณ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.