고객 테이블에 주민번호와 사업자번호가 같이 있다 기간계 시스템에서 흔히 보는 구조다. 고객 테이블 하나에 개인고객 속성(주민번호, 생년월일)과 법인고객 속성(사업자번호, 대표자명)이 섞여 있다. 개인고객이면 사업자번호가 NULL이고, 법인고객이면 주민번호가 NULL이다. 고객유형코드 컬럼 하나로 구분한다. 데이터가 적을 때는 별 문제가 안 된다. 고객이 수천만 건이 되면 이야기가 달라진다. 개인고객에만 필요한 컬럼이 법인고객 행에도 자리를 차지하고, 법인고객에만 필요한 컬럼이 개인고객 행에서 NULL로 비어 있다. 컬럼이 늘어날수록 테이블이 와이드해지고 의미가 흐려진다. “이 컬럼이 어떤 고객 유형에 해당하는지"를 DDL만 보고 알기 어렵다. 수퍼-서브 타입은 이 문제를 논리 모델 단계에서 정리하는 방법이다. 공통 속성과 고유 속성을 분리한다 수퍼-서브 타입의 원리는 간단하다. 공통 속성은 수퍼 타입(고객)에 두고, 유형별 고유 속성은 서브 타입(개인고객, 법인고객)에 둔다. [고객] ← 수퍼 타입: 고객ID, 고객명, 연락처 ├─ [개인고객] ← 서브 타입: 주민번호, 생년월일 └─ [법인고객] ← 서브 타입: 사업자번호, 대표자명 고객ID 하나로 수퍼 타입과 서브 타입이 연결된다. 개인고객 테이블에는 개인고객에만 해당하는 속성만 들어간다. NULL 투성이의 와이드 테이블이 사라진다. 서브 타입을 나누는 또 다른 이유가 있다. 서브 타입별로 다른 엔터티와 독립적으로 관계를 맺을 수 있다. 법인고객만 여신한도와 관계를 가진다든지, 개인고객만 멤버십 등급과 관계를 가진다든지. 수퍼 타입 하나에 모든 관계를 매달면 관계의 의미가 모호해지는데, 서브 타입으로 나누면 “이 관계가 어떤 유형에 해당하는지"가 모델에서 바로 읽힌다. 배타적인가, 중복 가능한가 서브 타입을 설계할 때 반드시 먼저 따지는 게 있다. 하나의 인스턴스가 서브 타입 중 정확히 하나에만 속하는지(Exclusive), 여러 서브 타입에 동시에 속할 수 있는지(Inclusive)다. Exclusive 가 압도적으로 많다. 고객은 개인 아니면 법인이다. 계좌는 보통예금, 적금, 정기예금 중 하나다. 상품은 실물이거나 디지털이다. 구분코드 하나로 분류가 끝난다. Inclusive 는 드물지만 빠뜨리면 나중에 큰 수정이 필요하다. 서비스 상품 같은 경우가 해당된다. 하나의 상품이 B2B 대상이면서 동시에 B2C 대상일 수 있다. 직원 역할도 마찬가지다. 한 사람이 영업과 기술지원을 겸하는 경우, “직원역할” 서브 타입이 Inclusive가 된다. 설계 초기에 “이 분류가 정말 배타적인가"를 한 번 더 따져야 한다. Exclusive로 전제하고 모델을 짰는데 겹치는 케이스가 나오면 구분코드 체계부터 관계 구조까지 뜯어고쳐야 한다. 물리 모델로 넘어갈 때의 선택지 논리 모델에서 수퍼-서브 타입은 깔끔하다. 물리 모델로 전환할 때 선택이 갈린다. 통합 테이블. 수퍼 타입과 서브 타입을 하나의 테이블로 합친다. 처음에 문제라고 했던 그 와이드 테이블이 되지만, 조인이 없어서 쿼리가 단순하다. 서브 타입별 고유 속성이 적으면 실용적인 선택이다. 개별 테이블. 수퍼 타입 테이블과 서브 타입 테이블을 각각 만든다. NULL이 없고 구조가 명확하지만, 고객 정보를 온전히 보려면 수퍼 타입과 서브 타입을 조인해야 한다. 서브 타입만. 수퍼 타입 테이블 없이 개인고객 테이블, 법인고객 테이블만 만든다. 공통 속성을 각 테이블에 중복으로 가진다. 서브 타입별로 완전히 독립적인 분석을 하는 경우에 맞지만, 고객 전체를 보려면 UNION이 필요하다. 정답은 없다. 서브 타입 수, 고유 속성의 양, 쿼리 패턴에 따라 달라진다. DW 차원 설계로 이어지면 DW에서는 이 선택이 차원(Dimension) 설계와 직결된다. 2편 에서 다뤘던 “접근 경로” 관점이 판단 기준이 된다. 고객 차원을 설계한다고 하자. 개인고객과 법인고객을 별도 차원으로 나누면 팩트 테이블에 FK가 늘어나고, 분석할 때 어떤 차원을 조인할지 매번 선택해야 한다. 통합 차원으로 만들면 NULL이 많은 와이드 테이블이 되지만, 1편 에서 다뤘던 것처럼 클라우드 Columnar Storage에서는 NULL 컬럼의 스캔 비용이 거의 없다. 판단 기준은 분석 패턴이다. 개인고객 매출은 연령대와 지역으로 보고, 법인고객 매출은 산업군과 매출 규모로 본다면 차원 속성 자체가 다르니 나누는 게 낫다. 고객 전체를 하나의 축으로 놓는 분석이 대부분이면 통합이 편하다. 실무에서 많이 보는 절충안은 통합 차원을 기본으로 두되, 서브 타입별 분석이 빈번할 때 별도 뷰나 마트를 추가하는 방식이다. 클라우드 환경에서 스토리지 비용이 낮으니 중복 저장 부담이 작다. 다음 글에서는 Inmon 방식과 Kimball 방식을 비교한다. 1편에서 간략히 언급했던 내용을 더 구체적으로 들어간다.