test - schema test, singular test, custom test, whatnot
dbt core - 오픈소스, CLI 기반, 로컬 개발
dbt cloud - SaaS, UI 제공, 스케줄링, 협업 기능
1. Incremental 2. Snapshot 3. Test 4. Airflow + dbt 운영
먼저 jinja 에 대해 알아보자
dbt 에서 자주 사용하는 sql 언어 포맷임
jinja 는 SQL 을 동적으로 생성하기 위한 템플릿 언어
dbt 가 Jinja를 만나서 jinja 를 실행하면 : select * from {{ ref('stg_orders') }} ↓ jinja 위치에 실제 SQL 이 생성되어 교체됨 : select * from analytics.stg_orders ↓ 그리고 warehouse 에서 실제 SQL이 실행됨(warehouse 는 jinja 해석 못 함. jinja 는 dbt 를 위한 것임)
1. {{}} : 표현식. 값을 출력할 때 사용함. {{}} 위치에 정해진 값이 변환되어 실행
예를 들어,
- {{ ref('stg_orders') }} 는 -> analytics.stg_orders 로 변환
- {{ target.schema }} 는 -> analytics_dev 로 변환
- {{ target.name }} 은 -> dev 혹은 prod 로 변환됨.
target.schema, target.name 은 profiles.yml 에 설정된 값을 가져오는 것
또한, dbt_project.yml 에 직접 넣은 값을 아래처럼 읽어올 수 있음
예를 들어 dbt_project.yml 에 아래 부분이 포함되어있다고 하자
vars: country: CA
모델.sql 내에서 다음과 같이 불러올 수 있음
select * from customers
where country='{{ var("country") }}'
2. {% %} : 제어문. 조건문, 반복문 등에 사용.
예를 들어,
jinja가 포함된 쿼리문
dbt 가 jinja 를 처리한 이후 쿼리문
select * from orders {% if target.name == 'prod' %} where is_deleted = false {% endif %}
< prod 환경일 때, where 문이 존재함 > select * from orders where is_deleted = false
위와 같은 config 를 줬기 때문에 dbt 가 어느 디렉터리에서 정보를 가져가야 할 지 알게 됨
이를테면, model-path: ["models"] 로 설정된 부분으로 인해, dbt 는 "model 들은 'models' 디렉터리 안에 있구나" 라고 인식함
models: my_project:
staging: +materialized: view +schema: staging
intermediate: +materialized: ephemeral
marts: +materialized: table +schema: marts
위 config 의 'models'는 'model 에 대한 설정'을 의미함
models 이하에 나오는 config 를 통해
각 models(SQL 파일들)을 어떻게 처리해야 할 지 알 수 있음
my_project 는 프로젝트 이름
위의 name: my_project 와 연결됨
(프로젝트 이름을 굳이 다시 넣었다는 말은.. dbt_project.yml 내에 여러 프로젝트의 config 가 들어갈 수 있다는 말인가?)
materialized 가 뭐하는거야?
SQL 결과를 warehouse 에 어떤 형태로 저장할지 결정하는 부분
SQL 을 실행한 후 결과를 table 로 만들 수 있고, view 로 만들 수 있고, 혹은 incremental table 로 만들 수 있음
잘 보면, 각각의 SQL 파일들마다 materialized 가 있는게 아니고, 각 단계(staging, intermediate, marts)마다 materialized 가 존재함
즉, materialized 는 하나의 단계 전체적으로 적용된다고 볼 수 있음.
만약 각 테이블마다 각기 다른 materialized 를 적용하고 싶다면
모델 SQL 파일 내에 {{ config(materialized='table') }} 처럼 적용하면 됨
이렇게 적용된 설정은, dbt_project.yml 에 설정된 materialized 보다 우선시됨.
대부분 materialized 는 dbt_project.yml 단위로 설정함
왜냐면 각 단계가 공통의 특징을 따르기 때문에.
참고로 dbt 의 기본 materialized 값은 view 임
model 내에 설정 > dbt_project.yml 내에 설정 > default(view)
+materialized : view
여기서 view 는 실제 데이터를 저장하지 않는 가상 테이블임.
create view 명령어 실행되어 생성되는 뷰 그거 맞음
query 실행되는 런타임마다 그때 그때 계산되어 생성 및 사용되기 때문에, 항상 최신 데이터를 갖고 있음
하지만 매 런타임마다 계산되기 때문에, select 퍼포먼스가 느림 실제 테이블을 만들지 않기 때문에 차지하는 storage 적음
심지어 view 는 BI tool 에서도 접근이 가능함. BI tool 이 view 테이블에 접근할 때마다 view 쿼리를 계속 재실행한다는 말이지.....
view 는 staging 처리할 때 자주 사용된다고 하는데.. 그 이유가, 굳이 물리적인 테이블을 만들 필요가 없어서..?
staging 을 위한 sql 이 비용이 적은 이유(타입 캐스팅 혹은 컬럼명 변경 등)는 알겠어
그래서 view 처럼 런타임에 실행해도 무리가 없다는 거지
근데 staging 은 ground truth 역할(lake 마냥)을 해야하기 때문에 무조건 물리적인 테이블로 만들어둬야 하지 않나?
+materialized : table
여기서 table 은 실제 데이터를 저장하는 물리적인 테이블을 의미함
따라서 storage 용량을 차지하며 생성될 때 갖고있는 데이터를 그대로 보관하게 되며
하지만 view 와 달리 select 실행시 재계산을 하지 않아도 되기 때문에 select 퍼포먼스가 빠름
아래 incremental 과의 차이점은?
+materialized : incremental
변경분만 table 에 업데이트 함. hudi 의 upsert 와 같은 느낌인거지
즉, 기존 테이블이 없으면 새로운 table 을 만들고
기존 테이블에 데이터가 없으면 새로 데이터를 추가하고
기존 테이블에 데이터가 있으면 변경된 부분만 업데이트 함
incremental 이 적용되는 model 쿼리를 한 번 보자
select * from orders where updated_at > ( select max(updated_at) from {{ this }} )
위와 같이 {{ this }} 를 통해 자기 자신 테이블에서 최신 날짜만 가져온 후
최신 날짜 이후로 들어온 데이터만 추출해서 incremental 로 업데이트
+materialized : ephemeral
실제 table이나 view 는 생성하지 않지만
SQL 내부에 inline 된다고....(????) ephemeral 로 설정된 model SQL 을 실행해도
warehouse 내에 object 를 생성하지 않음(그건 view 도 마찬가지잖아?-> 개발자 입장에서는 view 도 object를 만들지 않는것 처럼 보이는데, 실제로 warehouse 입장에서는 object 처럼 보인다고 함. 그래서 select * from my_view 같이 from 에 view 를 넣은 쿼리가 가능함)
다르게 말하면, ephemeral 로 만들어진 결과는 from 를 통해 불러올 수 없음(view는 이게 가능함)
ephemeral 로 설정된 model SQL 은 downstream SQL 에서 CTE 처럼 삽입된다고 함
위의 예제에서 intermediate 부분에 ephemeral 이 설정되어있고,
marts 에 table 이 설정되어 있잖아
intermediate 및 marts SQL model 이 아래와 같다고 하자
-- int_orders.sql
select customer_id, sum(amount) as total_amount from {{ ref('stg_orders') }} group by 1
-- fct_customer_revenue.sql
select * from {{ ref('int_orders') }} where total_amount > 100
이걸 실행시키면, ephemeral 로 설정된 int_orders 의 쿼리가 fct_customer_revenue 쿼리 안으로 쏙 들어감
select * from (
select customer_id, sum(amount) as total_amount from stg_orders group by 1
) as int_orders where total_amount > 100
이걸 보고 inline 이 된다고 한 거임....
view 랑 ephemeral 의 차이는 알았는데, 그럼 각각은 무슨 장단점이 있을까?
- view 는 warehouse 에서 조회가능한 object를 주르륵 만들기 때문에, 여러개의 view 를 만들면 지저분해질 수 있음
ephemeral 은 지저분하지 않음(....이게 장점인가?)
- ephemeral 은 object 생성이 어려우니 디버깅하기가 어려움.
즉, view 처럼 select 해서 직접 값을 볼 수 없으니 ephemeral 로직이 잘 실행되었는지 아닌지 몰라
- ephemeral 을 사용하면 하나의 큰 nested sql 이 생성됨. 한 번에 큰 계산을 하게되는 상황이 발생할 수 있음
- downstream 에서 동일한 ephemeral 을 여러번 사용하면, 중복 계산이 되기 때문에 퍼포먼스가 좋지 않음
그럼 ephemeral 은 언제 쓰는거야?
warehouse object 를 만들 가치가 없는 경우에 쓴다고 함
warehouse 안에 독립된 객체(table,view 등)으로 보관할 필요가 없을 때 사용
table, view 등의 객체는 select 로 조회가 가능하고
BI tool 에서 접근도 가능하고, 디버깅 대상으로 중요함
ephemeral 은 downstream 에 필요한 작은 조치를 취하는 쿼리를 시랳ㅇ
예를 들어 phone 넘버에서 '-' 를 제거하는 쿼리나
kg을 g으로 변환하는 쿼리 등
그래서 구우우욷이 warehouse 에 객체로 남기지 않아도 됨
select 로 접근할 필요가 없고 디버깅 할 필요도 없기 때문
< seeds >
이곳에 csv 파일을 넣어두면, dbt 가 warehouse 에 자동으로 upload 한다고 함
작은 reference table 을 만드는 용도로 사용한다고 함
예를 들어 아래와 같은 csv 를 파일을 넣어두면....
country_codes.csv currency_codes.csv
무슨 일이 벌어지지? 어느 db 에 만드는거야? 함부로 table 만드는 권한은 어떻게 갖고있는거지?
< tests >
custom test 를 저장하는 곳
예를 들어 아래와 같이 내가 원하는 테스트를 만들어 넣음
tests/ └── assert_positive_revenue.sql
select * from {{ ref('fct_orders') }} where revenue < 0
결과가 나타난다면, 실패하는 거임...
select * 의 결과가 나타나지 말아야 함
ref('fct_orders') 는 fact table 대상으로 테스트를 진행한다는 말이 될 것 같음
그럼 여기 tests 디렉터리 내에 있는 테스트와, schema.yml 내에 있는 테스트의 차이는?
< snapshots >
변경 이력 추적용이라는데 뭔 소린지 모르겠음
< analyses >
ad-hoc SQL 을 저장하는 곳이라는데 뭔 소린지 모르겠음
< ref() >
위에서 계속 봐왔겠지만, ref() 는 다른 모델의 객체(table, view) 를 가져오는 역할을 함
ref() 덕분에 데이터 모델 간 의존성(dependency)가 정의될 수 있음
가령, 아래와 같은 모델이 있다고 하자
fct_orders.sql
select * from {{ ref('stg_orders') }} where amount > 0
여기서 {{ ref('stg_orders') }} 의 의미는, "stg_orders 모델의 결과(stg_orders.sql 의 결과)를 참조" 임
위 fct_orders.sql 이 실행될 때, {{ ref('stg_orders') }} 위치에 stg_orders 의 결과(db.table) 로 치환됨
이를테면 "select * from sales_dev.stg_orders where amount > 0"
구체적으로 아래 단계를 따라서 ref() 가 실행됨
- dbt 가 ref('stg_orders') 발견
- stg_orders 모델이 존재하는지 확인
- dependency 에 등록
- 실제 relation 이름을 계산 (여기서 relation 이름은, stg_orders.sql 실행 결과의 db.schema.table 이름)
- fct_orders.sql 의 from 에 위치한 ref() 를 relation 이름을 치환
stg_orders.sql 에 업데이트가 발생해도 위 fct_orders.sql 은 그대로 stg_orders 의 결과를 참조함
가령 stg_orders.sql 의 결과 테이블 db 가 sales_dev 에서 sales_prod 로 바뀌어도
위 fct_orders.sql 은 영향이 없음
그리고 ref() 를 사용하는 더 중요한 이유, 바로 dependency graph 를 생성한다는 것
dbt 는 ref() 로 연결된 모델sql들을 보고 dependency graph 를 만듦
이에 맞춰 실행할 순서를 정함
만약 dependency graph 가 없으면, dbt 는 어떤 모델sql 을 먼저 실행해야할지 모르게 됨
- sources.tables.columns : source 데이터가 들어있는 테이블의 컬럼 정의 - sources.tables.columns.name : source 데이터가 들어있는 테이블의 컬럼 이름 - sources.tables.columns.tests : source 데이터가 들어있는 테이블의 컬럼 테스트 - sources.tables.loaded_at_field : source 데이터가 들어있는 테이블의 최신값 기준 컬럼 - sources.tables.freshness : source 데이터가 들어있는 테이블의 freshness 정의
위와 같이 정의된 source 테이블로부터 데이터를 읽는 dbt의 모델.sql 은 아래와 같음
select * from {{ source('raw', 'orders') }}
dbt 가 위 쿼리를 실행하면 아래처럼 해석하고 실행함
select * from analytics.raw.orders
dbt docs generate 를 통해 문서를 만들게 되면, source.yml 내용을 기반으로 문서에 '이런 곳에서 외부 데이터를 가져와!'라고 써 줌
테스트 실행 명령어 : dbt test
freshness 검사 실행 명령어 : dbt source freshness
< source() >
ref() 가 모델.sql 로부터 생성된 결과 객체를 참조하는 문법이라면,
source() 는 dbt 밖에 존재하는 원본 데이터를 참조하는 문법
즉, 모델.sql 에서원본 데이터를 읽을 때 source() 를 사용하고
모델.sql 에서upstream 모델.sql 을 읽을 때 ref() 를 사용함
예를 들어, source.yml 이 아래처럼 생겼고
version: 2
sources: - name: raw <- source 이름
database: analytics schema: raw
tables: - name: orders <- table 이름
이 orders 테이블로부터 데이터를 가져오는 모델.sql 쿼리는 아래와 같음
select * from {{ source('raw', 'orders') }} <- 첫번째인자 : source 이름, 두번째인자 : table 이름
여기서 orders 는 (dbt 와 연관없는) 외부에서 만들어진 테이블임
가령 spark, kafka 등이 warehouse 에 만든 테이블
그리고 우리는 source() 를 사용해서
dbt 에게 'raw 라는 이름의 외부 소스가 warehouse 에 존재하고, 거기에 'orders' 라는 테이블이 존재한단다'라고 알려주는 것임
다른 예제를 보자. source.yml 이 아래처럼 생겼고
sources: - name: raw
database: analytics schema: raw
tables: - name: orders - name: customers
이 orders, customers 테이블로부터 데이터를 가져오는 모델.sql 쿼리는 아래와 같음
select * from {{ source('raw', 'orders') }}
select * from {{ source('raw', 'customers') }}
source() 를 만나면, dbt 는 이 문장을 아래와 같이 해석하게 됨
select * from analytics.raw.orders
source freshness 라는 개념이 있음
'원본 데이터가 얼마나 최신인가?'를 검사하는 설정이라고 함
a->b->c 순으로 흐르는 stream 이 있는데 a 부분에서 데이터 공급이 멈추면,
b, c 도 데이터 처리를 못하게 될 것임
"데이터를 처리하지 못한 만큼의 시간"을 계산해서 조치를 취하는 것이 freshness 설정
a 가 들어오지 않으면 dbt 가 계속 실행하는 것에 의미가 없기 때문에 dbt run 을 중단하고 알람을 발생하도록 만들꺼야
즉, freshness 를 통해 에러 혹은 알람이 발생하면, 데이터 파이프라인이 죽었다고 생각할 수 있음
예를 들어, 아래와 같이 freshness 를 추가한 source.yml 이 존재한다고 하자
sources: - name: raw
tables: - name: shipments
loaded_at_field: updated_at
freshness: warn_after: count: 2 period: hour
error_after: count: 6 period: hour
updated_at 기준으로 데이터 최신성을 판단 할 것이고,
2시간 이상 최신 데이터가 들어오지 못하면 경고,
6시간 이상 최신 데이터가 들어오지 못하면 에러를 발생시키라고 설정한 내용
dbt source freshness 명령어로 실행
dbt 가 실제로 확인하는 것은 '현재 시간'-'마지막 업데이트된 시간' 의 차이임
마지막 업데이트 된 시간은 아래처럼 구함
select max(updated_at) from raw.shupments
정리하자면, source() (source.yml) 의 의의는
- 원본 데이터 문서화 : 외부 소스가 어디인지 알 수 있음
- Lineage 생성 : DAG 의 가장 처음 부분을 설정
- Data Quality Test : 테스트도 할 수 있나봄
- Freshness Monitoring : 데이터 적재 파이프라인 장애를 감지함
- 환경 분리 : Dev, Stage, Prod 를 분리. 그럼에도 source() 를 통해 모델.sql 에는 영향이 없음
< seed >
dbt 의 철학은 'warehouse 내에 존재하는 데이터(테이블)를 transformation 한다'임
그래서 source() 를 통해 외부로부터 가져온 데이터를 테이블로 만들고,
그 테이블로부터 dbt 작업이 시작됨
source() 를 통해 유입되는 raw 데이터는 kafka, spark 등을 통해 진행되는데
근데.. 국가코드, 환율매핑, 우편번호매핑 등 정적이고 이미 정해져있는 데이터들은
굳이 spark 를 사용해서 파이프라인을 만들고 warehouse 에 넣을 가치가 없음
따라서 dbt 는 자체적으로, 이런 정적이고 작은 csv 데이터를 warehouse 테이블로 만들어서 사용하는데
명령어를 실행하면 dbt 패키지 허브에서 소스코드를 다운함 프로젝트 내dbt_packages/dbt_utils폴더가 생성되며, 이제부터 dbt 모델.sql 안에서 다음과 같이 매크로를 바로 사용할 수 있음
-- 두 컬럼의 값을 합쳐서 고유한 ID(해시값)를 만드는 dbt-utils 매크로 사용 예시
select
{{ dbt_utils.generate_surrogate_key(['user_id', 'signup_date']) }} as user_hash_id,
user_id,
signup_date
from {{ ref('raw_users') }}
< dbt 명령어들 >
먼저 dbt 프로젝트 개발 흐름을 살펴보면
- 개발(모델.sql, yml 설정 등) -> compile 진행 -> run -> test -> docs 만들기 -> 배포
이 흐름대로 개발하며 필요한 dbt 명령어들을 알아보자
명령어
언제 사용되는가
의미
dbt run
특정 모델만 실행하려면 dbt run --select stg_orders
특정 계층(stage,intermediate 등)만 실행하려면 dbt run --select staging
개발(모델.sql, yml 설정 등)이 마무리 된 후 실행
dependency 순서대로 모델.sql 을 실행하고 dependency graph 를 만들고 warehouse 에 테이블을 만듦
모델.sql 을 create view, create table 명령어로 바꿔서 실행
테스트해주는 거 아님 freshness 검사해주는 거 아님 문서 만들어주는 거 아님
dbt compile
SQL 디버깅 할 때 사용 실제로 생성된 SQL 문을 눈으로 확인하며 디버깅 진행
jinja 를 실제 SQL 쿼리문으로 변환 이 명령문을 통해 나온 SQL 쿼리문은 target/compiled 에 저장됨
dbt test
배포하기 전에 실행 대개 dbt run -> dbt test 순으로 실행된다고 함
데이터 품질 검사 진행
sources.yml, schema.yml, seed, test 디렉터리 내 tests 를 실행 예를 들어, tests unique 는 group by id having count(*) > 1 을 실행하여 결과가 나타나는지 확인하는 것으로 테스트를 진행한다고 함
dbt build
dbt run, dbt test, dbt seed, dbt snapshot 모두 한 번에 실행
dbt seed
seeds/mycsv.csv 등 csv 파일을 테이블로 만들 때 사용
dbt source freshness
파이프라인의 가장 처음에 실행 source freshness 실행 -> dbt build(dbt run -> dbt test)
source 의 마지막 업데이트 날짜와 현재 날짜 간 차이를 계산하여 처리(경고 혹은 에러)
dbt docs generate
문서를 생성 생성된 문서는 lineage 를 포함하여 json 파일로 저장됨
target/catalog.json: 웨어하우스(데이터베이스)에서 추출한 테이블 및 스키마 메타데이터. target/manifest.json: 사용자가 작성한 dbt 모델, 테스트, 소스 및 DAG(계보) 정보. target/index.html: 문서 웹사이트를 렌더링하는 기본 UI 템플릿
dbt docs serve
프로젝트 분석이 필요할 때
문서 서버를 실행함 브라우저에서 Lineage Graph, Model Doc, Column Desc 등 확인
dbt ls
특정 계층의 모델만 보고싶다면 dbt ls --select staging
설정된 모델명들 나열
dbt debug
dbt 프로젝트의 전반적인 구성 확인
dbt 버전 확인: 현재 설치된 dbt 버전 정보 dbt_project.yml 검증: 프로젝트 구성 파일의 유효성 검사 profiles.yml 검증: 프로필 파일의 존재 여부 및 구문 검사 데이터베이스 연결 테스트: 웨어하우스 서버와의 통신 및 권한 테스트
dbt deps
packages.yml파일에 정의된 외부 패키지(매크로, 모델, 테스트 등)를 다운로드하여 설치하는 명령어. dbt 를 위한 기능을 다운받음.
- 비즈니스 프로세스 선택 : "고객의 결제(Point-of-Sale Sales)" 프로세스를 선택 왜냐면 이것이 매출 분석의 가장 기본이 되는 핵심 활동이기 때문
- grain 설정 : 영수증에 찍힌 개별 항목(Line Item) 하나를 grain 으로 설정
고객이 어떤 상품을 구매하였는지 row 단위로 알 수 있도록.
만약 '영수증 한 장'을 단위로 잡으면, 고객이 '커피 3잔', '라떼 2잔' 샀을 때 각각의 판매량을 분석할 수 없게 됨.
개별 아이템 단위로 잡아야 가장 세밀한 분석이 가능
- 차원 식별 : grain(영수증 항목)을 설명하기 위해 필요한 모든 관점을 나열 (누가, 언제, 어디서, 무엇을) 날짜(Date): 판매가 일어난 날짜 (연, 월, 일, 요일, 공휴일 여부 등) 시간(Time): 판매 시간대 (시, 분, 아침/점심/저녁 피크타임 구분 등) 매장(Store): 판매가 일어난 장소 (밴쿠버 지점, 토론토 지점, 매장 크기 등) 상품(Product): 팔린 물건 (아메리카노, 라떼, 사이즈, 카테고리 등) 결제 수단(Payment): 신용카드, 현금, 모바일 페이 등 프로모션(Promotion): 적용된 쿠폰이나 할인 이벤트 이름
- fact 식별 : 영수증 항목 하나당 기록될 '숫자(측정값)'를 정함 판매 수량 (Quantity): 몇 잔 팔렸나? (Additive) 총 판매 금액 (Gross Revenue): 할인 전 가격 (Additive) 할인 금액 (Discount Amount): 쿠폰 등으로 깎아준 금액 (Additive) 순 판매 금액 (Net Revenue): 실제 결제된 금액 (Additive) 단가 (Unit Price): 상품 하나당 가격 (Non-additive) - 합산하지 않고 참조용으로만 사용
최종 Fact Table 은 다음과 같이 생성됨
< Fact Tables 상세 : PK 로 사용할 컬럼 정하기 >
Fact Table, Dimension Table 모두 natural key 보다 surrogate key 를 사용하는 것이 좋음
(단, natural key 중 '날짜값'은 PK 로 사용 가능함)
- natural key 는 길고 복잡한 경우가 많기 때문에 상대적으로 간단한 surrogate key를 사용하는 것이 좋음
간단한 key 로 PK-FK 를 설정하게 되면 join 성능에 긍정적인 영향을 줌
- natural key 는 업데이트 되는 경우가 있기 때문에 변하지 않을 surrogate key 사용
- 여러 source 로부터 데이터를 가져왔는데 하필 natural key 들이 서로 겹치는 상황이 발생하는 경우
surrogate key를 사용하여 데이터를 구분할 수 있음
- natural key 가 '알 수 없음', null 등의 값일 때 surrogate key 를 사용하면 -1, 9999 등으로 대체해서 사용 가능
그럼 natural key 는 버려야하는가? 하는 질문을 할 수 있음
natural key 는 버려도 되지만, 비즈니스적 의미는 갖고 있기 때문에
look up 테이블 하나를 만들어서 surrogate key 와 natural key 를 연결시켜 natural key 도 남기는 방법을 추천함
분석가 등의 사용자 입장에선 surrogate key 보다 natural key 로 쿼리하는 것이 더 자연스러움
surrogate key 가 존재해도 natural key 의 '유일성'이 사라지는 것은 아니기 때문에
surrogate key (PK) 가 다르지만 동일하게 처리해야 하는 rows 를 natural key 로 묶어줄 수 있음
예를 들어 kim 이 이사가서 주소가 바뀐 경우(SCD type2로 처리)
Row 1: SK: 101, NK: kim@email.com, City: Vancouver, Current: N
Row 2: SK: 505, NK: kim@email.com, City: Toronto, Current: Y
이 때 Surrogate Key 는 서로 다르지만, Natural Key 는 동일하기 때문에
이 둘이 같은 사람이구나! 라는 것을 알 수 있음
또한, source DB 를 뒤져봐야 하는 경우 Natural Key 를 사용할 수 있음
왜냐면 surrogate key 는 우리가 만든 값이고 sourceDB 에는 없으니까
< Conformed Dimension Tables >
서로 다른 두 fact tables 이 공유하는 dimension table을 Conformed Dimension Tables 라고 하며,
서로 다른 두 fact tables 을 공통된 차원(예: 날짜, 매장 등)을 기준으로 연결하여 분석하는 행위를 Drill across 라고 함
이렇게 dimension 을 연결함으로써 두 가지 fact tables (위 예제의 sales 와 cost)를 같이 연결하여 분석 가능함
위와 같이, 날짜(Time/Date) dimension 을 연결함으로써,
각 월의 비용cost 과 판매sales 를 같이 비교, 분석 할 수 있음
위 스샷은 서로 다른 두 개의 fact tables 가 하나의 conformed dimension table 을 사용할 때
서로 다른 FK 를 사용하도록 설정된 것임
이게 가능한 이유는, dimension table 에 Date_FK 와 DateMonth_FK 가 join 할 수 있는 컬럼들이 모두 있기 때문
예를 들어,
- Sales Fact Table 과 조인할 때 : Fact_Sales.Date_FK (20220101) = Date_SK - Cost FactTable 과 조인할 때: Fact_Cost.DateMonth_FK (2022-01) = Month_SK
아래는 Drill Across 수행하는 SQL 예시
-- 1. 일 단위 매출을 월 단위로 집계
WITH monthly_sales AS (
SELECT d.Month_SK, SUM(s.amount) as total_sales
FROM Fact_Sales s
JOIN Dim_Date d ON s.Date_FK = d.Date_SK -- 일 단위 조인
GROUP BY d.Month_SK
),
-- 2. 월 단위 비용 집계
monthly_cost AS (
SELECT DateMonth_FK as Month_SK, SUM(cost) as total_cost
FROM Fact_Cost -- 이미 월 단위이므로 바로 집계
GROUP BY DateMonth_FK
)
-- 3. 공통 차원(Month_SK)을 기준으로 Drill Across
SELECT s.Month_SK, s.total_sales, c.total_cost
FROM monthly_sales s
JOIN monthly_cost c ON s.Month_SK = c.Month_SK;
비록 팩트 테이블에 저장된 FK의 형태나 상세도는 다르지만,
이들이 바라보는 Dim_Date라는 마스터 테이블은 하나임
두 팩트 테이블의 FK 값이 20220101과 2022-01로 서로 다르더라도,
이 값들이 동일한 차원 테이블의 유효한 키(혹은 속성)라면 Drill across 분석에 아무런 문제가 없음
FK의 모양이 같은 게 중요한 것이 아니라, 차원 테이블 내의 속성 정의(이름, 범위, 값의 의미)가 전사적으로 동일해야 함
< 그 외 Dimension tables 종류 >
- Degenerate Dimensions : 속성 정보가 거의 없고, 오직 식별 번호만 의미가 있는 경우
Dimension table 로 따로 설정하지 않고, 바로 fact table 에 직접 저장함
예를 들어 영수증 번호, 송장 번호 등
영수증 번호는 그 자체로 의미가 있을 뿐 추가로 설명할 속성이 없음
이를 위해 Dimension table 을 만들면 join 만 늘어남
(이런 개념이 왜 필요한거지? 왜 설명한거야 이건..? 그냥 fact table 의 일반적인 컬럼 중 하나 아니야?
-> 'dimension' 이라는 것은, 데이터를 식별하고 묶어주는 핵심적인 역할인데
영수증 번호, 송장 번호 등의 값은 'dimension' 역할이 가능하기 때문에 차원이라고 부르는 것임
표면상으로 보면 그냥 fact table 의 컬럼 중 하나일 뿐임)
- Junk Dimensions : fact table 에 있는 여러 개의 자잘한 flag, indicator 등을 모아둔 dimension table
Y/N, 1/0 등으로 나타나는 컬럼들.
예를 들어, 결제 여부(Y/N), 성별(0,1), 취소 여부(Y/N), 배송 여부(Y/N) 등
fact table 에서 발생 가능한 모든 조합(Y/Y/N, N/N/N, N/Y/Y 등)을 미리 계산해두고 dimension table 로 만들고 연결
왜 이렇게하느냐?
플래그들이 너무 많아서 Fact 테이블이 너무 넓어지는 것을 방지하기 위함
- Role-playing Dimensions : 하나의 Fact 테이블에서 여러 가지 역할로 재사용되는 Dimensions table.
예를 들어 fact table 에 주문일, 배송일, 결제일 세 가지 날짜 컬럼이 존재
그리고 우리는 Dim_Date 라는 dimension table 하나만 만들고, 주문일/배송일/결제일 분석에 사용.
JOIN Dim_Date AS Order_Date ON ... JOIN Dim_Date AS Ship_Date ON ...
동일한 구조와 데이터를 가진 dimension table을논리적으로 분리하여 사용.
이는 데이터 일관성을 유지하기 위함
< SCD(Slowly Changing Dimension) >
Dimension Table 데이터가, 시간이 지남에 따라 어떻게 변화를 관리할 것인가를 다루는 개념 Dimension Table 의 속성이 변경될 때, 그 변경 사항을 어떤 방식으로 반영할지를 정의하는 전략
어떤 전략을 사용할지 결정하는 것은 '비즈니스 사용자'들임.
분석가들이 '이력도 필요해요'라고 하면 type2를 사용하는 것이고
'절대 바뀌면 안 되는 값이에요' 하면 type0 을 사용하는 것이지
고객 정보, 제품 정보, 주소, 부서 같은 차원 데이터는 (자주는 아니고) 가끔씩 변하기 때문에 "Slowly Changing" 이라고 부름
주요 유형 (Type 0 ~ Type 3)
1. SCD Type 0 – 변경 없음 - 변경이 발생해도 원래 값을 그대로 둠.
- 데이터의 정체성을 유지하기 위함. - 예시: 생년월일, 최초 가입일, 원래 주문번호, 이름(고객 이름을 바꾸더라도, 데이터 웨어하우스에는 최초 등록된 이름만 저장)
2. SCD Type 1 – 덮어쓰기 (Overwrite) - 변경 발생 시 기존 값을 그냥 덮어씀. 과거 데이터는 사라지고, 항상 최신 상태만 유지. - 과거는중요하지않고최신 상태만 필요한 경우에 사용 - 예시 : 전화번호(과거 전화번호는 의미가 없음), 이메일 주소
고객 주소가 "서울" → "부산"으로 변경되면 차원 테이블에는 부산만 남음. "과거에 고객이 서울에 살았다"는 정보는 알 수 없음.
- 과거 데이터를 포함하여 집계하는 경우, (업데이트가 진행된)현재 속성이 적용되어 데이터 왜곡이 발생할 수 있음
즉, 과거 데이터 값들이 현재 정보 기준으로 집계되는 문제가 발생할 수 있음
3. SCD Type 2 – 이력 관리 (History Tracking). Default Strategy - 변경 발생 시 데이터의 과거 이력을 보존하기 위해새로운 row를 추가해서 이력 관리. - 과거 이력 분석이 필요한 경우 사용 - 보통 효력 시작일 (start_date) / 효력 종료일 (end_date) / is_current 같은 컬럼을 둠.
- 예시 : 고객 주소가 "서울" -> "부산" 으로 변경되었다면 차원 테이블에는 두 가지 row 가 다 들어있게 됨 고객 주소 create_time update_time is_current eye 부산 1991-06-25 2025-11-04 Y eye 서울 1991-06-25 1991-06-25 N
Product_SK Prod_ID (NK) Category Start_Date End_Date Is_Current 77 W-100 Electronics 2025-01-01 2026-04-15 N 89 W-100 Fashion 2026-04-16 9999-12-31 Y
dimension table 이 업데이트(동일한 제품의 카테고리만 업데이트) 된 이후
fact table 는Product_SK 가 77대신 89를 사용하여 row 를 만들게 될 것임
"W-100의 총 매출" 등의 쿼리를 하려고 where sk=89 처럼 쿼리하면 77을 갖고있던 row를 다 무시하게 될 것임
이런 경우, natural key를 사용하여 dimension table PK 는 다르지만 서로 동일한 제품이구나!를 파악함
예를 들어,
SELECT D.prod_id, SUM(F.amount) FROM fact_table F JOIN dim_table D
ON F.product_fk = D.product_sk WHERE D.Prodid = 'W-100'
GROUP BY D.prod_id
- 예시 : 고객 주소가 Vancouver 에서 Toronto 로 변경되었다면,
과거가 되어버린 데이터의 end_date 를 "변경된 날의 어제 날짜(yesterday)" 로 설정하고
새롭게 추가된 데이터의 start_date를 "변경된 날" 로 설정. end_date는 먼 미래로 설정
Customer_SK Email (NK) City Start_Date End_Date Is_Current
101 kim@mail.com Vancouver 2025-11-01 2026-02-02 N
505 kim@mail.com Toronto 2026-02-03 9999-12-31 Y
만약 "kim 의 총 매출을 보여주고, 현재 어느 도시(Toronto)에 사는지도 같이 표시해줘" 라고 쿼리해야 한다면
is_current 가 y 인 것을 추가로 필터링해줘야 함
예를 들어,
SELECT d_curr.email, d_curr.city AS current_city, -- 현재 살고 있는 도시(Toronto) SUM(f.sales_amount) AS total_sales FROM fact_sales f JOIN dim_customer d_all ON f.customer_sk = d_all.customer_sk -- 과거/현재 모든 SK와 조인하고 그리고 JOIN dim_customer d_curr ON d_all.email = d_curr.email -- 같은 이메일 중 AND d_curr.is_current = 'Y' -- 현재 유효한 행의 정보만 가져옴. GROUP BY d_curr.email, d_curr.city; -- is_current='Y' 에 매칭되는 email, city 단 하나씩만 나옴.
이 예제에서 총 세 개의 테이블이 합쳐짐
1. fact_sales (fact_table) : d_all 과 조인되어, dim_customer 정보를 모두 fact_table 로 가져옴
2. d_all : 아무런 필터나 추가 조치없이 그냥 fact_table 에 그대로 존재하는 dimension table
3. d_curr : is_current='Y' 인 email 과 city 만 갖고옴. d_all 와 join 후, d_all 의 모든 row 에 매칭됨
End_Date 를 '9999-12-31' 처럼 현재 유효한 데이터의 종료일을 크게 잡은 이유는,
쿼리에서 WHERE '2026-04-24' BETWEEN Start_Date AND End_Date 처럼
특정 시점의 유효 데이터를 찾기 매우 편해지기 때문
최신 정보만 필요할 때, WHERE Is_Current = 'Y' 필터를 걸어 성능 최적화 가능
4. SCD Type 3 – 제한된 이력 관리 - 변경 전/후 값을 컬럼으로 저장. 행을 새로 만들지 않고, 테이블에 '이전 값(Previous Value)' 컬럼을 추가하여 이력 관리
- 두 번 이상 업데이트하면 과거 데이터부터 소실됨 - 예시 고객 현주소 전주소 eye 부산 서울
< 논리적 성능 최적화 >
kimball 모델링을 따라 fact, dim tables 를 star schema 로 만든다고 하자
- dim table 에 Surrogate Key 를 사용
이유는 위의 "< Fact Tables 상세 : PK 로 사용할 컬럼 정하기 >" 부분을 참고
- 비즈니스별로 SCD type 을 고려
history tracking 이 필요한 비즈니스에서는 type2가 필요하지만
굳이 필요없다면 공간 낭비, search query 성능 낭비해가면서 history 를 유지할 필요 없는 type1 사용
- snowfalke schema 보다는 star schema (비정규화 진행)
dim table 내 데이터 중복 관리와 사이즈가 커지는 문제보다, join 으로 인한 성능 하락 이슈가 더 크리티컬하기 때문
< 물리적 성능 최적화 >
kimball 모델링을 따라 fact, dim tables 를 star schema 로 만든다고 하자
- Partitioning, Bucketing
fact tables 를 날짜 단위로 파티셔닝함(물론 '날짜' 뿐만 아니라 cardinality 가 낮은 '지역' 등으로 해도 됨..)
partition pruning 을 통해 IO 를 획기적으로 줄일 수 있음
하지만 cardinality 가 높은 key 로 파티셔닝하게되면 small file problem 을 발생시킬 수 있으니 조심
메타데이터를 통해 모든 파일에 다 A 가 존재하는 것을 보고 모든 파일을 다 열어보게 됨 (=full scan)
File 1: region (metadata Min: A, Max: D) -> "A가 구간 안에 있네? 읽어야 함" File 2: region (metadataMin: A, Max: D) -> "A가 구간 안에 있네? 읽어야 함" File 3: region (metadataMin: A, Max: D) -> "A가 구간 안에 있네? 읽어야 함" File 4: region (metadataMin: A, Max: D) -> "A가 구간 안에 있네? 읽어야 함"
WHERE region = 'A' 같은 쿼리를 날리면 메타데이터를 통해 몇몇 파일에만 A 가 존재하는 것을 보고 필요한 파일들만 열어보게 됨
File 1: region (Min: A, Max: B) -> "A가 구간 안에 있네? 읽음" File 2: region (Min: C, Max: D) -> "A가 구간 밖에 있네? 안 읽음" File 3: region (Min: A, Max: B) -> "A가 구간 안에 있네? 읽음" File 4: region (Min: C, Max: D) -> "A가 구간 밖에 있네? 안 읽음"
이렇게 보면 효율이 좋지만, 반대로 생각하면, 날짜 기준으로 쿼리했을 때 성능이 떨어진다는 단점이 있음
z-ordering 을 고려해야하는 상황은, 다양한 컬럼으로 where 조건을 걸고 검색하는 경우가 잦을 때.
Z-Ordering 와 파티셔닝과 차이점 :
- 파티셔닝은 디렉토리를 물리적으로 쪼개는 것
- Z-Ordering은 파일 내부의 데이터를 재배치하여 메타데이터(Min/Max)의 효율을 극대화하는 것
1. 비즈니스 프로세스 선택 (Select the Business Process) 이 파트에서는 'raw 데이터로부터 어떤 집계를 할 수 있을까' 하는 의문에 답을 해 봄
계좌이체 데이터가 있으니, '흠, 시간대별 자금이 어떻게 흐르는지 확인할 수 있겠군',
'아니면 은행 간 거래 비중이 얼마나 되는지 볼까?',
'혹은 송금 실패율을 확인해볼까?' 등을 꼽아볼 수 있음
그래서 비즈니스 프로세스는 '자금 이체(Fund Transfer) 이벤트'
2단계: grain 설정 (Declare the Grain)
이 파트에서는 가장 낮은 수준으로 fact table 의 row 를 구성할 수 있도록 설정함
즉, "한 명의 사람이 하나의 방법으로 다른 한 사람에게 이체한 기록 한 건" 처럼 가장 작은 단위를 grain 으로 설정할 수 있음
grain 은 이렇게 설정해두고, '일일 송금 한도'나 '월간 총 이체액' 같은 건 나중에 집계해서 보게 됨
3단계: 차원 식별 (Identify the Dimensions)
고정값을 갖는 dimension 으로 그룹지을 수 있는 컬럼들을 묶어서 dimension table 로 만듦 날짜시간(Date/Time), 보낸이(Sender), 받는이(Receiver), 거래 수단(Transfer Method), 은행정보(Bank), 거래 상태(Status) 여기서 보낸이, 받는이는 하나의 dimension table 로 처리 가능하기 때문에, Role-playing Dimension table 로 사용 가능
4단계: 사실 식별 (Identify the Facts)
분석의 대상이 되는 '측정 가능한 수치값'들을 여기에 넣으면 됨
이체 금액(Amount), 거래 소요 시간(Latency), 수수료(Fee)
상식적으로 생각해서, dimension table 에 들어가면 길이가 엄청 길어지겠다..싶은 것들은 fact table 에 남겨둬야 함
이체금액 정보 같은 데이터는 계속해서 생성되는 정보니까 당연히 fact table 에 넣어야 함
아래와 같이, 미리 연/월/일/요일/분기 등 다양한 시간 속성을 미리 만들어두면 쿼리 성능과 편의성이 크게 향상되기 때문
CREATE TABLE dim_date ( date_key INT NOT NULL PRIMARY KEY, -- 고유키 (예: 20230101) full_date DATE NOT NULL, -- 실제 날짜 (YYYY-MM-DD) year INT NOT NULL, -- 연도 quarter INT NOT NULL, -- 분기 month INT NOT NULL, -- 월 (1~12) month_name VARCHAR(15) NOT NULL, -- 월 이름 (January, 1월 등) day_of_month INT NOT NULL, -- 일 (1~31) day_of_week INT NOT NULL, -- 요일 (1=일, 7=토) day_name VARCHAR(15) NOT NULL, -- 요일 이름 (Monday, 월요일 등) is_weekend BOOLEAN NOT NULL -- 주말 여부 );
1. 비즈니스 프로세스 선택 (Select the Business Process) 'raw 데이터로부터 어떤 집계를 할 수 있을까' 하는 의문에 답을 해 봄 해당 데이터는 광고가 노출 및 클릭 될 때마다 기록되니, '시간대별, 일별, 월별 광고 클릭률(ctr)을 계산해볼 수 있겠다', '아니면 어느 위치의 광고가 가장 많이 클릭되는지 집계해볼까?' 등을 생각해볼 수 있음
그래서 비즈니스 프로세스는 '광고 성능 측정' 혹은 '광고 성과 측정(Ad Performance Tracking)'
2. Grain 설정
가장 낮은 단위로 진행해야하므로
'한 사람이 하나의 광고를 하나의 디바이스에서 하나의 위치에서 한 번 클릭/노출한 단위'를 grain 으로 설정
위 raw data 그대로 사용해도 될 것 같음
3. dimension 식별
묶을 수 있는 것들을 묶어보자.
날짜별로 묶을 수 있고, 유저 정보로 묶을 수 있고..(근데 이 raw 에는 유저정보가 별로 없어서 묶어도 큰 의미는 없을 듯)
광고 정보로 묶을 수 있고, 광고 매체로 묶을 수 있고, 캠페인 정보로 묶을 수 있음
여기서 '캠페인'이라는 개념을 알고 있어야 dimension 으로 묶이겠구나 라고 판단 가능
따라서 비즈니스를 잘 이해하고 있어야 함
dim_ad_creative: 광고 소재 정보 (소재Surrogate Key, 광고주명, 배너사이즈, 카테고리 등) dim_campaign: 캠페인 정보 (캠페인SK, 캠페인명, 시작일, 종료일, 목표 등) dim_publisher: 매체 정보 (매체SK, 사이트URL, 도메인 카테고리 등) dim_date: 날짜 정보 (날짜SK, 연, 월, 일, 분기, 요일 등)
4단계: fact 식별
분석의 대상이 되는 '측정 가능한 수치값'들은 클릭 횟수, 노출 횟수, 비용 등.
클릭/노출 될 때마다 쌓이게 되니까 fact table 에 있어야 함
(고정 비용이라면 dimension 에 있어도 될 것 같은데, 고정 비용이 아니라면 fact table 에 있어야 할 듯)
If the jobsat the head of the queuedon't need to use the whole cluster, later jobscan start to run right away
대기열의 맨 앞에 있는 jobs 후속 jobs
then later jobs may be delayedsignificantly significantcomputing resources may berequired.
상당히 지연될 수 있다. 상당한 컴퓨팅 자원이 요구될 수 있다.
This featureis disabledby default.
기본적으로 비활성화되어있다.
Newly submitted jobs go into a default pool.
새롭게 제출된 작업들은 default pool에 들어간다.
Jobs runin FIFO order Jobs runin order. Automate A, B, and Cin order of importance. data is stored in chronological order
FIFO 순서로 작업이 실행된다. 순서대로 작업이 실행된다. 중요한 순서대로 자동화하라 시간순으로 저장되어있다
both of these together make up the node Distributed storage refers to a storage architecturemade up ofmultiple computers and disks.
노드를 만든다. 다양한 컴퓨터와 디스크로 구성된 저장 아키텍처
The same is true ofthe C node.
C노드도 마찬가지다.
Our managers deal with all kinds of clients every day
매일 다양한 clients 를 상대한다.
In my previous projectIcarried outthe responsibilities of...
나의 이전 프로젝트에서, 이러이러한 책임을 수행했다.
Project managers usually estimate new projects by analogy
유사사례를 통해 신규 프로젝트를 추정한다.
I improved my time management and organizational skills.
시간 관리 및 시간 정리 능력을 향상시켰다.
the server performsinstructionswritten in code.
명령을 수행한다.
use only the numbersin given array. Cardinality refers to the number of unique values in a given dataset.
주어진 배열 내 숫자만 사용하라 카디널리티(Cardinality)는 특정 데이터 집합에서고유한 값(unique values)의 개수를 의미한다.
I assigned the number 33 to age variable.
나이 변수에 33을 할당했다.
I created an array of strings.
문자열 배열을 생성했다.
Debugging is toinvestigatethe program and fix bugs.
프로그램을 조사하는 것이다.
A programcrasheswhen you divide by zero.
프로그램이 중단된다.
I declared a function and implemented it. It works well!
함수 하나를 선언했고 구현했다. 잘 동작한다.
I instantiatedanother object of the Student class.
또 다른 학생 클래스 객체를 인스턴스화했다.
I iterated(loop) through every element in the list.
리스트 내 모든 요소를 순회했다.
Processing is manipulation of data by a computer
컴퓨터에 의한 데이터 조작이다.
Raw data can be converted into JSON format.
Josn 형태로 변환될 수 있다.
Maintainability : It should be stable when the changes are made
변경사항이 적용되었을 때 안정적이어야 한다.
You need a dedicated work space
전용 작업 공간
Let'smoveour meetingback an hour.
한 시간 미루자
Shemovedthe meetingupa day.
미팅을 하루 앞당겼다.
The meetingwas rescheduled forThursday.
회의가 목요일로 재조정되었다.
From asubjectiveperspective.
주관적인 관점에서
We will meet in a week and synchronize on the progress.
진행 상황을 맞춰보자.
Big dataenablesyoutogather data from many sources.
데이터를 수집할 수 있게 한다.
A kafka topicis identified byits name Each brokeris identified withits ID.
카프카 토픽은 이름으로 식별된다.
The sequence of messages is called a data stream Sequential messages received messagesin sequence. processing data sequentially is necessary
메세지의 순서를 데이터 스트림이라고 부른다. 연속된 메세지들 순서대로 수신한 메세지들 연속으로 데이터를 처리하는 것이 필요하다.
Topicsare split inpartitions.
토픽은 파티션으로 나뉘어진다.
Each message gets anincrementalid, called offset. 'Append' adds only the newly arrived dataincrementally
하나씩 증가하는 id 'Append' 는 새로 추가된 데이터를 증분으로 추가한다.
Kafka topics are immutable
토픽들은 불변한다.
Data is kept only for a limited time. Data is maintained only for a limited time. Data remained only for a limited time.
데이터는 제한된 기간 동안만 보관된다. 데이터는 제한된 기간 동안만 유지된다. 데이터는 제한된 기간 동안만 남아 있는다.
Over time, the kafka clients have been changed.
시간이 지남에 따라...
The processing of rapidly increasing datais entrusted to Hadoop. Idelegatedthe task to Hadoop
빠르게 증가하는 데이터 처리를 하둡에게 맡긴다. 하둡에게 그 일을 위임했다.
There are two main methods fordata transmission.
The "streaming type" continuously transmits data as it is generated, in real time.
실시간으로 생성되는 데이터를 끊임없이 보내는 방법이다.
Data collected over the past 30 minutes is aggregated If you want to graph the event trendover the past hour..
지난 30분동안 모은 데이터들이 집계되었다. 과거 1시간의 이벤트 수 추이를 그래프로 만들고 싶으면..
To analyze datafrom the past 3 years
지난 3년간의 데이터를 분석하기 위해
Amazon S3 isa representative example ofobject storage.
대표적인 객체 스토리지다.
it can increase data capacity in the future.
향후 데이터 용량을 증가시킬 수 있다.
Most people are accustomedto using SQL
SQL 사용에 익숙하다.
This series of procedures is called the ETL process
일련의 절차를 ETL 프로세스라고 부른다.
Batch processing is executed according to a fixed daily schedule
고정된 일일 일정에 따라 실행된다.
If an error occurs, the administrator is notified.
관리자에게 알려진다.
System failures can occur during big data processing. Therefore, it is necessary toimplement functions to handleand retry tasks when errors occur.
처리하는 기능을 구현하는 것이 필수다.
Data collected throughout the day is aggregated overnight to generate reports.
하룻동안 수집된 데이터들은 밤사이 집계된다.
Unprocessedraw data is stored in a data lake, and only the necessary data is retrieved and used later.
미가공한 원시 데이터가 data lake 에 저장된다. 그리고 필요한 데이터만 추출된다.
Data engineers are responsible for building, managing, and automating the systems.
데이터 엔지니어는 책임을 진다.
It’s best to start with a small system and gradually scale it up over time.
나중에 단계적으로 확장해가는 것이 좋다.
In the early stages, manually collecting and analyzing data without automation is called ad hoc analysis.
시작 단계에서..
Searching for data that meets specific criteria
특정 기준을 충족하는 데이터 검색하기
values in the 'time' column can be tricky to handle
time 컬럼값은 다루기가 까다롭다
The same aggregation is repeated on a regular schedule—weekly or monthly—to observe trends over time.
1개월 혹은 1주일마다 정기적인 일정으로 동일한 집계를 반복하고 그 추이를 관찰한다
the number of adimpressions.
광고 노출 수
The number of customers who used the service in a day. The number of customers who used the servicewithin a day.
하루에 서비스를 이용한 고객 수 (하루 전체. 통으로) 하루 이내에 서비스를 이용한 고객수 (24시간 이내에)
Making decisions based on objective data is called data-driven decision making.
객관적인 데이터를 근거하여판단하는 것을 '데이터 기반 의사 결정'이라고 한다.
the values in A column aregenerallyhigher/lower/similar to the values in B column.
전체적으로
As long as you have organized numerical data
정리된 숫자 데이터가 있다면
names arelisted in rows, and sales arelisted in columns.
행 방향으로 나열되고, 열 방향으로 나열된다.
the numeric data appearsat the intersections of rows and columns
행과 열의 교차점
large datasets that can't fully fit in memory Loadall the datainto memory.
메모리에 다 들어가지 못하는 큰 용량의 데이터 모든 데이터를 메모리에 올린다.
If the wait time for aggregation increases, all processes slow down.
대기시간이 늘어나면, 모든 작업들이 느려진다.
your system needs to be designed for it from the start.
처음부터 그렇게 디자인되어야 했다.
fast data processing is described as having low latency.
'지연시간(latency)이 적다'고 표현된다.
a sharp drop/improvementin performance
급격한 성능 저하/향상
The amount of data that can be processed within a certain period of time is called "throughput".
일정 시간 내에 처리할 수 있는 데이터의 양을 처리량(throughput)이라 한다.
The time you wait for data processing to complete is called "latency".
작업이 끝날 때 까지 대기하는 시간을 지연시간(latency)이라 한다.
The presence or absence of indexes Which option to choosedepends on the situation.
인덱스 유무 어떤 옵션을 선택할지는 상황에 따라 달라진다.
a query is broken down into many smaller tasks
다수의 작은 태스크로 분해된다.
you need to scale both CPU and disk resources in a balanced way.
균형있게 자원을 늘려야한다.
exploring the data through repeated trial and error.
반복적인 시행착오를 통해
In contrast to ad hoc analysis, you can run queries on a regular schedule to generate reports.
ad hoc 분석과 대조적으로..
you want to take your time and carefully examine the data.
시간을 갖고 차분히 데이터를 보고 싶다.
Metric B is updated once a day.
B 메트릭은 하루에 한 번 업데이트 된다.
improvements in computing power
컴퓨팅 성능 향상
There are more/fewer cases now where building a data mart is unnecessary.
이러한 경우가 늘어나고/줄어들고 있다.
Normalization involves splitting tables as much as possible and linking them using foreign keys.
Denormalization involves combining tables as much as possible.
tables are categorized into fact tables and dimension tables.
Fact tables store data that accumulates over time.
시간에 따라 증가하는 데이터가 저장된다.
Dimension tables typically store attributes used to categorize the data.
A model where a fact table is surrounded by multiple dimension tables is called a star schema.
Files are replicated across multiple machines to increase redundancy.
중복성을 높이기 위해 파일을 복사한다.
jobs are preferably executed on nodes close to the data.
가급적, 데이터와 가까운 노드에서 실행한다.
spontaneously simultaneously
자발적으로 동시에
resourcecontention(competition) occurs between jobs
자원 쟁탈(경쟁)
they run only whenno one else is using the resources.
누구도 자원을 사용하지 않을 때만
Spark keeps intermediatedata in memory It is safer to process data in an intermediatetable first
중간 데이터를 메모리에 보존한다. 중간 테이블을 만들어 처리하는 게 안전하다.
problems arise when aggregating large amounts of data over a long period.
장기간에 거쳐
data isevenlydistributed across all nodes
균형있게 분산되어있다.
storage and compute nodes are tightly coupled
밀접하게 결합되어있다.
it either waits for resources to free up or fails with an error.
메모리가 생길 때까지 기다리거나
memory usage doesn’t increaseproportionally
비례하여 늘어나지 않는다.
memory consumption remains nearly constant
메모리 사용량은 거의 일정하게 유지된다
You can aggregate data with millions of records in under one second
수백만 레코드를 갖는 데이터를 1초 미만으로 집계할 수 있다.
Even if a partial failure occurs, processing can continue as a whole
부분적으로 장애가 발생해도, 전체적으로 처리를 계속할 수 있다.
Tez is a replacement for MapReduce and inherits its fault tolerance. Tezis an alternative toMapReduce.
Tez 는 MapReduce 를 대체하는 것이며, 그 내결함성을 계승하고 있다.
Prestois the complete opposite ofHive
presto 는 hive 와 완전히 반대입니다
Presto is specialized for executinginteractive queries.
Presto 는 대화식 쿼리의 실행에 특화되어 있다.
excessive usage can prevent other queries from running. Excessively reducing cardinality can lead to significant information loss
무리한 사용 카디널리티를 무리하게 낮추면 원래 있던 정보가 크게 손실된다
it handles schema changes more flexibly.
스키마 변동에도 유연하게 대처할 수 있다.
frequentread/write operations on small amounts of data
빈번하게 소량의 데이터를 읽고 쓰는 것
It increasesthe rate ofunexpected errors. the likelihood of unexpected errors increases.
예상치 못한 오류 발생률을 높인다.
It's a design issuerather thana performance problem. Massive data should be divided and processed in parts rather than all at once
성능 문제라기보다는설계 문제이다. 한 번에 처리하기보다는부분으로 나눠서 처리해야한다.
What is the optimal file size for efficient processing?
효율적으로 처리할 수 있는 파일이 크기는 얼마나 될까?
These two differ entirely in both technical characteristics and tools used, so you must understand their nature and use them accordingly.
이 둘은 기술적인 특성도, 사용되는 도구도 전혀 다르므로 그 성질을 이해한 다음에 구분해서 사용해야 한다.
When handling large volumes of data, break tasks into monthly or daily units to prevent any single task from becoming too large.
한 달 혹은 하루 단위로 전송하도록 태스크를 분해하여, 너무 커지지 않도록 막는다.
Fluentd only sends messages in one direction
일방적으로 발송하는 것밖에 하지 못한다
mobile apps often go offline the device isback online.
모바일 앱은 오프라인이 되는 경우가 종종 있다. 다시 온라인 상태가 된다.
It can focus solely on its own tasks while leaving the rest to the shared system.
작업에만 오롯이 전념할 수 있고, 나머지 작업은 공통 시스템에 맡길 수 있다.
the two are in a trade-off relationship
둘은 트레이드오프 관계에 있다.
you justreacheda performance limit
성능 한계에 도달했다.
regulate the data write rate.
데이터 쓰기 속도를 조절하라
you need to decide in advance how to operate the system in its absence.
그것이 없을 때 어떻게 시스템을 운용할지 미리 결정해야한다.
Only keep the IDsreceivedwithin the last hour, and allow duplicates thatarrived later. Allowduplicatesforlate-arriving messages.
최근 1 시간 동안 받은 ID 만 기억해두고, 그보다 늦게 온 메세지의 중복은 허용한다.
The time a message is generated on the clientis called “event time,” (on the client side)
the time the server processes the message is called “process time.”
the data is arranged inacontiguous layout.
데이터가 연속적으로 배치되어있다.
Eventual consistency guarantees that all replicas will eventually converge to the same value over time.
시간이 지나면 결국 동일한 값으로 귀결된다.
Strong consistency guarantees that all read operations reflect the most recent write.
가장 최근의 쓰기를 반영한다.
a human intervenes to resolve the issue.
사람이 개입하여 문제를 해결한다.
Some tasks can cause new problems if they are not completed bythe scheduled time
예정된 시간까지 끝내지 않으면 새로운 문제를 일으키는 태스크도 있다.
Let's finish itwithin the allotted time.
정해진(할당된) 시간 내에 끝내자.
There are tools that notify you when a task exceedsits expected execution time.
작업이예상 실행 시간을 초과할 때 알려주는 도구가 있다.
It is important to anticipate potential unexpected errors in advance
예기치 못한 오류 발생 가능성을 예상하는 것은 중요하다.
Settingthe retry interval of a taskto10 minutes
작업의 재시도 간격을 10분으로 설정
“Backfill” refers to rerunning tasks over a specific periodby changing the date parameterin sequence.
‘백필’이란 파라미터에 포함된 날짜를 순서대로 바꿔가면서 일정 기간의 태스크를 다시 실행함을 의미한다.
You can test backfill gradually
테스트 삼아 조금씩 백필을 실행할 수 있다.
In Airflow, scripts must be written withatomicity and idempotency
Airflow 에서는 원자성과 멱등성을 갖춘 스크립트를 작성해야 한다.
it helps improve stability.
안정성을 높인다.
An execution with this propertyis called an idempotent operation.
이런 특성을 지닌 실행을 idempotent operation 이라고 한다.
'replacement'yields the same result even when repeated
'치환'은 반복해서 실행해도 동일한 결과를 산출한다.
Increase the number of retrieswhile gradually expanding the interval between them
재시도 횟수를 늘림과 동시에, 조금씩 재시도 간격을 넓혀나가라
automatic retries must be disabled, and recovery should be done manually in case of failure.
자동 재시도는 반드시 무효로 하고, 오류 발생 시 수작업으로 복구한다.
Adjust each task so that it has an appropriate size.
각 태스크가 적절한 크기가 될 수 있도록 조정한다.
nodes are connected by arrows, and these connections never form cycles.
노드와 노드가 화살표로 연결되며 각 노드 연결이 순환되지 않는다.
We can reprocess datastarting from 7 days ago.
7일 전 데이터부터 재처리할 수 있다.
A fast-response databaseis placed in the serving layer
서빙 레이어에 응답이 빠른 데이터베이스를 설치한다
Since the results of stream processing are used only temporarily, slight inaccuracies are acceptable.
스트림 처리의 결과는 일시적으로만 사용되며, 정확하지 않아도 큰 문제가 없다.
Handling messages with a large gap between processing time and event time is referred to as the out-of-order data problem.
프로세스 시간과 이벤트 시간의 차이가 큰 메세지를 처리하는 것을 ‘out of order’ 데이터 문제라고불린다.
they must be sorted by event time before aggregation
이벤트시간 순서로 정렬하고 집계한다.
Therefore, the system must retain the state of past events and re-aggregate the corresponding window whenever new data arrives.
때문에 과거 이벤트의 상태를 보존하면서, 데이터가 도달할 때마다 해당 윈도우를 재집계한다.
Since data cannot be stored indefinitely, data that arrives too late beyond a certain time threshold is ignored.
데이터를 무한히 계속 보관할 순 없으므로 일정 시간 이상 늦게 온 데이터는 무시한다.
In ad hoc data analysis, interpreters are preferred.
ad hoc 데이터 분석에서는인터프리터를 선호한다.
Each tweet is formatted as JSON data with a variable length.
각 트윗은 길이가 일정하지 않은 json 데이터로 되어 있다.
Virtual machines allow the entire team toshare a consistent setup
팀 전원이 같은 환경을 공유할 수 있게 해준다.
extracting data for a specified period The error occurredunderthe specified conditions.
명시된 기간 만큼의 데이터 추출하기 명시된 조건에서 발생했다.
overwriting adesignated partition
지정된 파티션 덮어쓰기
As long as the parameters remain the same
파라미터만 같다면
The functions executed at this time are serialized and lazily evaluated
이 때 실행되는 함수는 직렬화되어 지연 평가된다.
If the schedule is set to @daily, the task for January 1st is executed at the moment January 2nd begins. there is a one-day gap
스케줄이 @daily 라면, 1월 1일의 태스크가 실행되는 것은 다음 날 1월 2일이 되는 순간이다. 1일의 차이가 있다.
if more tasksare queued, they are put on hold untilslots become available.
그 이상의 태스크가 등록되면 빈 자리가 생길 때까지 실행이 보류된다.
Adjust task durations so that each one doesn’t take too long
각 태스크의 실행 시간이 길어지지 않도록 조절하라
It hasn't been that long.
그렇게 오래되진 않았어.
keep the systemina relaxed state.
항상 여유 있는 상태를 유지하라
By automating what was previously a manual reprocessing task
이전에 수동으로 처리해야 했던 작업을 자동화함으로써
a single re-runhandles all necessary steps
필요한 모든 과정을 처리했다.
IfI were asked to handletuning, my approach would be: first, measure and identify the bottleneck by profiling, then research best practices or consult documentation, and validate improvements step by step.
I’d definitely want to confirmthe original intentbefore making any changes.
반드시 원래 의도를 확인하겠다.
Iwas tasked withbuilding a data pipeline
데이터 파이프를 구축하게 되었음
To ensure idempotency, it deletes existing data for each date and regenerates it
날짜 단위로 기존 데이터를 삭제하고 새로 데이터를 만듦
there was no process in place to verify data quality.
데이터 품질 검사를 위한 프로세스가 마련되어 있지 않았다.
Iidentified and resolved the root causesof the inconsistency
원인을 발견하고 해결하였다.
The source team’s table had a different primary key (PK) configuration,causingduplicate records.
데이터 복제를 발생시켰다.
Some data was missing because their encryption logicmalfunctionedduring transmission
암호화 로직이 잘못 적용되어있었다.
we began receivingaccuratedataconsistently.
정합성있는 데이터를 받을 수 있게 되었다.
Icarried out a data cleansing processto remove orobscurePII where it would not affect business decisions.
PII 를 제거하거나 가리기 위해 클렌징 작업을 수행했다.
Imasked the middle part of names with starstoobfuscatethe PII.
모호하게 하기 위해 이름 중간 부분을 별표로 가렸다.
Iapplied a retention policyto PII,performing a soft delete forany PII older than three months from the current date.
PII 에 retention policy 를 적용하여 현재 날짜로부터 3개월이 지난 모든 PII에 대해 소프트 삭제를 수행했다.
I checkedcross-version backward compatibilitywithin the EMR environment to ensure there would be no issues after the upgrade.
업그레이드 후 문제가 발생하지 않도록 EMR 환경 내에서 버전 간 하위 호환성을 확인했다.
I thenprovisioned a new EMR cluster with the latest version
그런 다음 최신 버전으로 새 EMR 클러스터를 프로비저닝했다.
There were KTLO (Keep The Lights On) jobsscheduled by time,similar to crontab
crontab 처럼, 시간으로 스케줄링 해 둔 KTLO 작업들이 존재함
if an upstream job failed,itcaused downstream failures.
상위 작업이 실패하면 하위 작업의 실패를 초래했다.
Imodified the code to be idempotent
코드를 멱등성을 갖도록 수정했다
This reduced human error and improvedoperational efficiency.
인적 오류도 감소하고 운영 효율성이 향상되었다.
I willproactivelyseek out and learn technologies I haven't used before.
사용해 보지 않은 기술을적극적으로찾아 배울 것이다.
I will invest time to take online courses, research best practices, and get hands-on experimentation.
온라인 강좌 수강, 모범 사례 연구, 그리고 직접적인 실험을 위해 시간을 투자할 것임
I will ensure no disruption to my work.
업무에 차질이 없도록 하겠다.
work with BA and DS teams, andrespond to their requests.
업무요청 대응하기
Itook overthe task of synchronizing data
데이터 동기화 작업을 인수인계 받았다
Occasionally, incorrect data wouldcome infrom the source table
가끔씩 소스 테이블에서 잘못된 데이터가 들어오곤 했다
we only found outdays later.
우리는 며칠이 지나서야 알게 되었다.
he told me to retrieve the data for that date again and move it to the target table.
그 날짜의 데이터를 다시 가져와서 옮기라고 말했다.
arbitrarily moving past date data would break consistency.
임의로 과거 날짜 데이터를 이동하면 일관성이 깨질 수 있다.
I learned that rather than just following instructions blindly, I must double-check whether my work is correct
맹목적으로 따라하지 말고, 내가 하는 일이 잘 하는게 맞는지 재확인
To minimize risk, I created isolatedtest resources like adedicatedEMR cluster.
전용 EMR cluster 같이, 분리된 테스트 리소스를 생성했다
Once validated, Isafely switched over
테스트가 마무리 된 이후 새로운 테이블을 기존 테이블로 안전하게 교체하였다
All team members wanted toswitchdirectly to Spark 3 without testing
This could lead to a dangeroussituationwhere the entire operation halts
이는 전체 작업이 중단되는 위험한 상황으로 이어질 수 있다.
onceI was assigned to handleWebUI processing using Spring. I was assigned the taskof adding functionality todisplay different screensbased on user permissions
Spring을 사용한 WebUI 처리를 담당하도록 배정받았다. 사용자 권한에 따라 다른 화면을 표시하는 기능을 추가하는 작업을 맡게 되었다.
I conducted code reviews with team members to double-check for any shortcomings.
부족한 점이 없는지 다시 한번 확인했다.
I performeda staging deploymentto verify that the screens displayed correctly for users with different permissions.
화면이 올바르게 표시되는지 확인하기 위해 스테이징 배포를 수행했다.
I received negative feedback regarding time management.
시간 관리에 대해 부정적인 피드백을 받았다.
I missed the deadline while waiting for approval and received feedback thatIfailed to meet timelines.
승인을 기다리다 마감일을 놓쳤고 일정을 지키지 못했다는 피드백을 받았다.
I need approval toproceedwith my work I applied for approval in advance and requested it multiple times but the response came late
업무 진행을 위해 승인이 필요하다. 사전에 승인을 신청하고 여러 차례 요청했다 하지만 답은 늦게 도착했다.
I willbe comfortable working independentlyand handling tasks reliably.
독립적으로 업무를 수행하고 신뢰할 수 있게 업무를 처리하는 데 익숙해 질 것이다.
I want to participate in decisions aboutfuture directionand contribute to the team's future.
향후 방향에 관한 결정에 참여하고 팀의 미래에 기여하고 싶다.
My biggest strength isidentifying inefficienciesin systems and improving them.
I’ve developeda strong habit of documentation and logging.
I'll share my thoughtsalong withthematerialsI researched and gathered beforehand.
사전에 조사하고 수집한 자료와 함께 내 생각을 공유할 것이다.
ROW_NUMBER() assigns a unique sequential number to each row,regardless of whetherthe values are the same.
값이 같은지 아닌지 상관 없이
DENSE_RANK() assigns the same rank to rows with the same value, andthe next rank is assigned without gaps.
다음은 갭 없이랭크가 부여된다
RANK() assigns the same rank to rows with the same value, butit leaves gapsin the ranking sequenceafter ties.
같은 값을 갖는 랭크 이후 갭이 있다
Window functions are functions that preserve the context of the original data and do not reduce the number of rows after aggregation.
집계 후에 원본 데이터 맥락을 유지한다.
JOINcombines columnshorizontally based on a condition, while UNION combines rows vertically and requires schema compatibility.
EXISTS ignores null values because itdetermineswhether a row exists.(The existence of a row)
EXISTS 는 행 존재 여부를 판단하기 때문에 null을 무시함
but I understand the concept and have worked on similar problems
I’m not familiar with that term, so I don’t want to give an incorrect explanation.
If it’s something I’ve encountered beforeunder a different term,I’d be happy to explain from that perspective.
혹시 제가 알고있는 개념이라면 보충해서 이야기를 할 수 있을 것 같다
I haven’t worked withStreaming Systemyet, so I wouldn’twant to explain itinaccurately.
If your team uses Streaming System in production, I’d make sure to study by watching online lectures, understand how I can use and why it was chosen here, and get hands-on experience soI can work with it safely in a production environment.
I haven’t had hands-on experience withperformance tuning yet.However, I have similar experiencein terms oftuning.
I can’t sayfor certainwhat theexact reasoningwas.
정확한 이유가 무엇이었는지 단정할 수 없다.
However, based on my understanding of the system, one possible reason could be cost efficiency in this part
하지만 제가 이해한 시스템 구조상 이 부분에서는 비용 효율성이 한 가지 이유가 될 수 있다
I didn’t design it myself, so I’d avoid making assumptions.
The requester wanted dataprocessed withthe desired transformation and wished to receive the data via SFTPaccording to a set schedule. Throughout this process,the requester and I discussed how to handle duplicate data, the final number of files,and how to notify us if issues occur.
요청자는 원하는 변환 방식으로 처리된 데이터를 원했으며, 정해진 일정에 따라 SFTP를 통해 데이터를 수신하기를 원했다. 이 과정 전반에 걸쳐 요청자와 저는 중복 데이터 처리 방법, 최종 파일 수, 문제 발생 시 통보 방식에 대해 논의했다.
We conducted many tests and completed the work as the requester wanted. As a result, I successfully built the data pipeline, and the requester receivedthe desired data.
우리는 여러 차례 테스트를 수행하고 요청자가 원하는 대로 작업을 완료했습니다. 그 결과, 데이터 파이프라인 구축에 성공했으며 요청자는 원하는 데이터를 수령했습니다.
Just retrievethe data for the date the issuewas created
이슈를 만든 날짜의 데이터를 찾아라.
Iproceededwith the task that way
그 방식으로 작업을 진행했다.
Therefore,arbitrarilymovingpast date datawould break consistency.
따라서 과거 날짜 데이터를 임의로 이동하면 일관성이 깨질 것이다.
We only discovered this much later.
그제서야, 나중에야, 뒤늦게서야...(아쉬움)
S3 doesn't have the concept of directories.
s3 는 디렉토리 개념이 없다
Durability refers tothe potential fordata loss. Durability refers tothe likelihood ofnot lossing data. Availability refers tothe probability ofbeing able to read data without issues.
Durability : 데이터를 잃어버릴 가능성. 99.999999999% Availability : 데이터를 문제없이 읽을 수 있는 확률
We canusetags asindicatorsfordistinguishing pusrposeswhensettling accountslater.
s3 bucket 에 tag 를 달면, 나중에 정산할 때 구분을 위한 지표로사용 가능함
Glue Crawlers parse andinfer from the csv file
Glue Crawlers 는 이 csv 파일의 정보를 분석하고 추론함
It remembers how far it previously collected data and resumes collection from the point where it stopped.
Apache Spark is a distributed data processing framework designed for large-scale data processing. It provides in-memory computation, fault tolerance, and a high-level API, which makes batch and iterative workloads much faster compared to traditional MapReduce.
What is the difference between RDD and DataFrame?
RDD is a low-level API that provides fine-grained control but lacks automatic optimization. DataFrames are higher-level, schema-aware, and benefit from Catalyst Optimizer and Tungsten execution engine, so they are generally preferred for most workloads.
What is lazy evaluation in Spark?
Spark does not execute transformations immediately. Instead, it builds a logical execution plan and only triggers computation when an action is called, which allows Spark to optimize the execution plan.
What is the difference between transformation and action?
Transformations define how data should be processed and are lazily evaluated, while actions trigger the actual execution and return results or write data.
Explain Spark’s execution flow.
When an action is called, Spark creates a job, which is divided into stages based on shuffle boundaries. Each stage consists of tasks that are executed in parallel on executors.
What is a shuffle and why is it expensive?
A shuffle involves redistributing data across executors, usually during joins or aggregations. It is expensive because it requires disk I/O, network transfer, and serialization.
What causes shuffle in Spark?
Operations like groupBy, reduceByKey, join, distinct, and repartition can trigger shuffle because they require data to be reorganized across partitions.
How do you optimize joins in Spark?
I try to reduce shuffle by using broadcast joins when one dataset is small enough. I also ensure proper partitioning and avoid skewed join keys when possible.
What is data skew and how do you handle it?
Data skew occurs when a few keys dominate the data distribution, causing some tasks to take much longer. Common approaches include salting keys, filtering hot keys, or using broadcast joins.
What is partitioning and why is it important?
Partitioning determines how data is distributed across executors. Proper partitioning improves parallelism and resource utilization, while poor partitioning can lead to performance bottlenecks.
What is the difference between repartition and coalesce?
repartition increases or decreases partitions and triggers a shuffle, while coalesce typically reduces partitions without a full shuffle.
When would you cache or persist data?
I cache data when it is reused multiple times across different actions, especially if the computation is expensive. I choose the storage level based on memory availability.
How does Spark handle failures?
Spark uses lineage information to recompute lost partitions. If a task or executor fails, Spark retries the task automatically on another executor.
Why is Parquet commonly used with Spark?
Parquet is a columnar storage format that supports compression and predicate pushdown, which reduces I/O and improves query performance.
How do you debug a slow Spark job?
I start by checking Spark UI to identify slow stages or skewed tasks, then review shuffle size, partition count, and executor utilization before applying optimizations.
Spark execution model 종류 및 차이
Spark execution flow (논리적 모델, 물리적 모델, stage, task 등)
partition, parallelism. input 파일 개수와 partition 의 관계?
join 종류와 어떤 상황에서 어떤 join 을 선택해야 하는지
executor 실패시 어떻게 되는지, 어떻게 복구할건지
skew 발생시 어떻게 대응할지
Why is this spark job slow? 느려지는 경우 어디서부터 어떻게 원인 찾고 해결할래?