dbt๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๊ณ ์๋ค๋ฉด ์ด๋ฏธ ์ํ๊ณ ์๋ ๊ฒ๋๋ค. ๐
๊ทธ๋ฐ๋ฐ dbt์๋ ๋ฐ์ดํฐ๋ฅผ ๋ ๊นจ๋ํ๊ณ ์ ๋ขฐํ ์ ์๊ฒ ์ ์งํ๋ ๊ฐ๋ ฅํ ํ ์คํธ ๊ธฐ๋ฅ๋ ์๋ค๋ ๊ฑฐ, ์๊ณ ๊ณ์ จ๋์?
์ด๋ฒ ๊ธ์์๋ ๋ค์์ ๋ค๋ฃน๋๋ค:
- โ ๊ธฐ๋ณธ dbt ํ ์คํธ โ ๋น ๋ฅด๊ฒ ์ ์ฉ ๊ฐ๋ฅํ ๊ธฐ๋ณธ๊ธฐ
- ๐ ์ค๊ธ ํ ์คํธ โ ์ฌ์ฉ์ ์ ์ ๋ก์ง๊ณผ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋งคํฌ๋ก
โ ๊ธฐ๋ณธ dbt ํ ์คํธ (Built-in)
dbt๋ ๋ชจ๋ธ์ .yml
ํ์ผ ์์์ ๋ฐ๋ก ์ฌ์ฉํ ์ ์๋ ๊ธฐ๋ณธ ํ
์คํธ๋ค์ ์ ๊ณตํฉ๋๋ค. ์์:
version: 2
models:
- name: customers
description: ๊ณ ๊ฐ ๋ง์คํฐ ํ
์ด๋ธ
columns:
- name: customer_id
tests:
- not_null
- unique
- name: email
tests:
- not_null
๐ง ๊ฐ ํ ์คํธ๊ฐ ํ๋ ์ผ:
not_null
: ์ปฌ๋ผ์ NULL ๊ฐ์ด ์๋์ง ํ์ธunique
: ๊ฐ์ด ๊ณ ์ ํ์ง ๊ฒ์ฆaccepted_values
: ํ์ฉ๋ ๊ฐ๋ง ํฌํจ๋์ด ์๋์ง ์ฒดํฌrelationships
: ์ธ๋ ํค๊ฐ ์ฐธ์กฐ ๋์ ํ ์ด๋ธ๊ณผ ๋งค์นญ๋๋์ง ํ์ธ
accepted_values
์์
- name: status
tests:
- accepted_values:
values: ['active', 'inactive', 'suspended']
์ด๋ฐ ๊ธฐ๋ณธ ํ ์คํธ๋ค์ ์์ฐ ๋์๋ณด๋์ ์ค๋ฅ๊ฐ ๋ฐ์๋๊ธฐ ์ ์ ๋จ์ํ ๋ฐ์ดํฐ ์ด์์ ๋น ๋ฅด๊ฒ ์ก์ ์ ์์ต๋๋ค.
๐ ์ค๊ธ dbt ํ ์คํธ (์ฌ์ฉ์ ์ ์ + ์ฌ์ฌ์ฉ ๊ฐ๋ฅ)
๊ธฐ๋ณธ ํ ์คํธ๋ง์ผ๋ก๋ ๋ถ์กฑํ ๋๊ฐ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด:
- ํน์ ๊ธฐ๊ฐ ๋ด ์ค๋ณต ์ฌ์ฉ์ ์กด์ฌ ์ฌ๋ถ ํ์ธ
- ์ฃผ๋ฌธ ์ด์ก์ด ๊ฐ ํญ๋ชฉ์ ํฉ๊ณผ ์ผ์นํ๋์ง ๊ฒ์ฆ
- ์ฌ์ฉ์๋น ํ๋์ ํ์ฑ ๊ตฌ๋ ๋ง ํ์ฉ
์ด๋ด ๋๋ ์ฌ์ฉ์ ์ ์ SQL ํ ์คํธ์ ๋งคํฌ๋ก๋ฅผ ํ์ฉํ๋ฉด ๋ฉ๋๋ค.
๐งช ์ฌ์ฉ์ ์ ์ SQL ํ ์คํธ ์์
tests/
ํด๋์ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํฉ๋๋ค:
-- tests/one_active_subscription.sql
SELECT user_id
FROM {{ ref('subscriptions') }}
GROUP BY user_id
HAVING SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) > 1
๊ทธ๋ฆฌ๊ณ .yml
์์ ํธ์ถ:
- name: user_id
tests:
- one_active_subscription
ํ์ฑ ๊ตฌ๋ ์ด 2๊ฐ ์ด์์ธ ์ ์ ๊ฐ ์๋ค๋ฉด ํ ์คํธ๊ฐ ์คํจํ๊ฒ ๋ฉ๋๋ค.
๐งฐ ๋ณด๋์ค: ํ๋ผ๋ฏธํฐํ๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋งคํฌ๋ก ํ ์คํธ
์ฌ๋ฌ ๋ชจ๋ธ์์ ์ซ์ ์ปฌ๋ผ์ด ํญ์ ์์์ธ์ง ๊ฒ์ฆํ๊ณ ์ถ๋ค๋ฉด?
Jinja ๋งคํฌ๋ก๋ก ๋ค์๊ณผ ๊ฐ์ด ์์ฑ:
-- macros/test_positive_values.sql
{% test positive_values(model, column_name) %}
SELECT *
FROM {{ model }}
WHERE {{ column_name }} < 0
{% endtest %}
๊ทธ๋ฆฌ๊ณ .yml
์์ ์ฌ์ฉ:
- name: price
tests:
- positive_values
์ด์ ํ ๋ฒ ์ ์ํ ํ ์คํธ ๋ก์ง์ ์ฌ๋ฌ ๋ชจ๋ธ/์ปฌ๋ผ์ ์ฌ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค.
dbt ์ปค์คํ ํ ์คํธ์ ๋งคํฌ๋ก ์ฐจ์ด
dbt ์ฌ์ฉ์ ์ ์ SQL ํ
์คํธ๋ ํน์ ๋ชจ๋ธ์ ํนํ๋ ์กฐ๊ฑด์ ํ์ธํ๋ ๋จ์ผ .sql
ํ์ผ์
๋๋ค.
๋ฐ๋ฉด์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋งคํฌ๋ก ํ
์คํธ๋ Jinja ๋งคํฌ๋ก๋ก ์์ฑ๋๋ฉฐ, ์ฌ๋ฌ ๋ชจ๋ธ/์ปฌ๋ผ์ ํ๋ผ๋ฏธํฐ๋ก ์ ์ฉํ ์ ์์ด ๋ ์ ์ฐํ๊ณ **DRY(Donโt Repeat Yourself)**ํฉ๋๋ค.
ํน์ ํ ์ผ์ด์ค์๋ SQL ํ
์คํธ, ์ฌ๋ฌ ๊ณณ์ ๊ณตํต์ผ๋ก ์ ์ฉํ ๋ ๋งคํฌ๋ก ํ
์คํธ๋ฅผ ์ฐ๋ ๊ฒ ์ข์ต๋๋ค.
๐งต ๋ง๋ฌด๋ฆฌ ์ ๋ฆฌ
์์ค | ์ฌ์ฉํ๋ ๋๊ตฌ | ์์ |
---|---|---|
๊ธฐ๋ณธ | ๋ด์ฅ YAML ํ ์คํธ | not_null , unique , accepted_values |
์ค๊ธ | ์ฌ์ฉ์ ์ ์ SQL/๋งคํฌ๋ก | positive_values , one_active_subscription |
์ฒ์์ ์๊ฒ ์์ํ์ธ์. not_null
๊ณผ unique
๋ง ์ ์ฉํด๋ ํฐ ์ฐจ์ด๋ฅผ ๋ง๋ญ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ ์ ๋ณต์กํ ํ
์คํธ ๋ก์ง์ ์ถ๊ฐํด๋ณด์ธ์.
๋ฏธ๋์ ๋น์ ๊ณผ ํ์๋ค์ด ์ง์ง๋ก ๊ฐ์ฌํ ์ผ์ ๋๋ค.
โ๋ง๊ฐ์ง ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ๊ฑฐ์ง๋งํ์ง ์๋๋ค. ๋จ์ง ๋น์ ์ ์ธ๋ด์ฌ์ ์ํํ ๋ฟ์ด๋ค.โ
dbt๋ก ์ฆ๊ฑฐ์ด ๋ฐ์ดํฐ ํ ์คํธ ๋์ธ์! ๐งช