원티드랩 데이터 마트 — 설립기

Jayeon Choi
원티드랩 기술 블로그
6 min readNov 24, 2023

들어가며

데이터 마트란 운영상 생성된 데이터를 변환, 집계하여 분석을 위해 운영 데이터를 가공한 데이터셋을 의미합니다. 조직의 성공을 위해 데이터 기반으로 의사결정을 주도한다는 점을 고려할 때, 운영 데이터보다 더 중요하거나 “중심”이 되는 정보라고 생각할 수 있습니다.

어떻게 만들었나?

먼저 원티드랩에 입사했을 때 데이터팀에서는 이미 데이터 웨어하우스(DW)로 구글 빅쿼리를 사용하고있었습니다. 구글 빅쿼리는 스키마 기반 SQL을 사용하여 데이터를 관리 할 수 있는데, 운영 데이터를 모두 빅쿼리에 쌓아두고 자주 필요한 테이블-컬럼들은 팀원들께서 뷰테이블로 구조화를 해 두셨죠.

원티드랩 기업 특성상 기업과 유저 단 데이터를 모두 갖고있고, 서비스 각각의 세부 데이터까지 처음부터 인지하기에는 다소 어려움이 있었는데 이미 만들어두신 뷰테이블의 코드를 뜯어보면서 사용빈도가 높은 테이블과 컬럼들을 먼저 파악하기 시작했어요.

구조화 하는 과정

1. ERD 만들기

우선 전체적인 큰 그림을 파악하고자, 뷰테이블에 사용된 원천 테이블들을 나열하고 그 테이블들 간의 ERD(Entity Relationship Diagram)를 그려보았습니다. 제가 사용했던 툴은 draw.io 였는데, github랑 연결도 되고 컨플루언스에도 붙혀넣어 볼 수 있어서 채택하게 되었어요. (다만 유지보수하면서 업데이트하기가 조금 번거로워서 지금은 좀 더 좋은 툴을 찾고있습니다. 사용하고계신 좋은 도구가 있으면 소개 부탁드려요 🤗)

ERD를 그리면서 테이블간의 관계도를 살펴보니, 테이블 구조화 뿐만아니라 각 테이블과 컬럼들의 설명이 좀 더 보완되어야 구성원들이 잘 이해하고 사용할 수 있을거라 생각했습니다. 모든 기업이 그렇듯 빠르게 성장하다보면 모델링하고 운영하기에 바빠 내부 인프라 사용성까지 챙길 여력이 없었을테니까요.

ERD에서 확인한 아래의 정보들을 토대로 앞으로 만들어야 할 테이블들의 작업 우선순위를 나누기 시작했어요.

  • Key값: Primary Key, Foreign Key 등
  • Mapping Cardinality
  • 컬럼의 타입

2. 코드작업

2–1. 고려한 점

마트 테이블을 관리할 때 가장 중요하게 생각한 부분은 앞으로의 확장성, 독립성, 그리고 품질 이었는데요. 각각의 포인트들을 기준으로 어떻게 코드를 짜려고 했는지 정리해볼게요.

  • 확장성
    서버팀의 강려크한 유지보수 체계로 인해 원천 테이블 자체가 자주 바뀌는 일은 없지만, 분석용으로 사용하는 테이블은 사용량이 많아짐에 따라 컬럼과 타입을 유연하게 변경하는 것이 구성원들이 활용하기에 편리할 것이라고 판단하였습니다. 그래서 같은 성격의 컬럼들을 테이블 단위로 묶어 추가/수정 할 수 있게 구현하였어요. 예를들면 User테이블에는 온전히 유저 정보만 추가될 수 있데 그루핑을 한 것이죠.
  • 독립성
    테이블 간 중복되는 컬럼은 PK외에는 없도록 설계하고, 1:多 관계가 아니라면 독립적인 하나의 행만 가질 수 있도록 json 타입이나 python 코드로 컬럼을 새로 추가해서 구현했습니다. User 테이블에 작성한 이력서 정보라던지 지원한 회사 정보는 별도 테이블로 구현하는 식으로요.
  • 품질
    믿고 쓸 수 있는 데이터를 만들어야 원천 데이터와 동일한 조건으로 추출할 수 있기 때문에 구조화 할 때 가장 중요하게 생각한 부분이었는데요. 예를들면 아래와 같은 현황을 파악하고 최대한 쿼리 작성에 편리하게 만들었습니다. 이 부분에서 분석가/구성원들과 커뮤니케이션에 많은 시간을 썼던 것 같네요 🥰

품질을 보증하기위해 아래와 같이 준수해야할 규칙을 정했습니다.

  1. 컬럼 사용 기준을 정하기
    — 서류 합격의 기준을 서류합격시간 컬럼의 유무(null값)로 보고계신지, 상태값으로 보고계신지
    — timestamp 기준을 UTC로 맞추기
  2. 쿼리 사용 현황 확인하기
    — 빈번히 사용중인 함수

2–2. 관리방식 정하기

기존 쿼리 베이스 마트 구조에서는 유지보수하기 힘든 몇가지 애로사항이 있었습니다.

  • 쿼리 비용
    뷰테이블 구조상 쿼리를 돌릴 때마다 조회되기 때문에 from 절에 마트 테이블을 조회하게되면 뷰테이블이 매번 실행되는 부분이 비용적으로 점차 부담되었습니다.
    앞으로 추가되는 테이블들이 많아질 것을 대비해 확장성을 고려해야했습니다.
  • 실행 소요시간
    하나의 테이블을 만들 때 원천 테이블 join이 많아지면, 원하는 데이터를 추출할 때에도 조회해야 할 테이블이 많아졌습니다(연쇄작용 🥲). 매번 테이블 조회를 할 경우에는 시간도 그만큼 오래 걸리기 때문에 잘못 실행시키거나 여러번씩 실행시켜야하는 경우 불편함을 방지할 수 있는 방법을 찾게되었습니다.

그래서 기존 방식을 Airflow DAG를 만들어 스케쥴러로 실행시키는 방식으로 변경하였고, 이 작업은 데이터 엔지니어분께서 아주 빠르게 작업 환경을 구축해 주셨습니다 👏🏼 Python 코드 베이스로 쿼리를 불러와서 컬럼도 원하는 조건대로 만들고 타입들도 가공할 수 있는 환경이 되어, 좀 더 유연한 마트 작업 환경이 만들어져서 기쁩니다 💖

2–3. 컬럼명 규칙(taxonomy) 정하기

테이블을 구성하기 위해 코드를 짜기 시작했는데, 여러 원천 테이블에서 참조하는 경우가 많다보니 컬럼명만 보고도 직관적이고 타입 출처를 짐작할 수 있는 네이밍 규칙을 정하는게 좋겠다 싶었습니다.

  • 컬럼명은 snake_case를 기준으로 합니다.
  • 모든 테이블의 PK: 테이블명_id
  • 테이블 간 join은 PK, FK 이용
  • timestamp 날짜 컬럼: UTC 기준으로 통일
  • true/false 값을 가지는 컬럼명: is_ 접두사 사용
  • analytics_mart에서 user, company, position, apply, order, event와 같이 서비스의 핵심 기능이 되는 테이블에 해당하는 컬럼은 축약어를 사용하지 않고 그대로 컬럼명 prefix로 적용
  • ex. apply 테이블 내 유저 정보 컬럼 : user_xxx
  • 3rd-party 툴이나 다른 테이블의 정보를 불러오는 컬럼일 경우, 접두사로 출처 확인
    (마트 데이터셋의 주 테이블 기준은 페이지 상단 접힌 컨텐츠 항목 참조)
  • ex. 크레딧잡 출처 : kj_xxx, 앰플리튜드 출처 : amp_xxx
  • 집계함수를 사용한 컬럼은 접두사로 표기
  • count() : c_ , sum() : s_

그래서 위와 같이 유지보수 할 때에 지켜질 수 있도록 네이밍 규칙을 만들어두었습니다.

앞으로의 마트는?

초반에는 품질 검증이나 테이블 구조 변경과 같은 자잘한 수정 요청을 받았습니다. 그래서 이제는 마트를 만들 때 확인해야 할 절차를 만들고, 그 규칙들을 준수하여 유지보수하고있어요. 충분히 테스트했다고 생각했는데, 사용하다보면 나오는 그런 이슈들.. 있잖아요… (인내하며 수정요청이슈 올려주시는 분석가분들, 구성원들께 항상 감사한 마음 🫂)

모든 검증과정과 확인을 거친 후에 배포된 마트 테이블은 구성원들께서 대시보드도 만들고, 데이터 추출을 위한 쿼리, 데이터 볼트라는 GPT 기반 슬랙봇 등에 활용되고 있습니다 👍🏼

테이블의 구조가 점점 방대해지면서 보완해야 할 부분들도 많은데요. 원천 테이블의 행 수가 큰 테이블은 업데이트 시간을 단축시킬 수 있는 방법(페이징), 마트 테이블 구조를 쉽게 파악할 수 있는 방법, 마트 테이블 수정과 테스트를 좀 더 편하게 할 수 있는 방법 등을 데이터팀 구성원들과 계속해서 유지보수 해 나가고 있습니다.

이번 편에서 다룬 마트 설립기 스토리를 읽어주셔서 감사합니다. 다음 편에서는 유지보수하는 과정을 다뤄보도록 할게요! 😃

매달 한 부 씩 일하면서 얻은 인사이트를 발행하고있습니다. 관심있으신 분들께서는 저를 구독해주세요! 🤗

--

--