슈퍼-서브테이블을 언제 사용해야 할까?
현재 결제 수단인 Key와 PointKey 그리고 로그들을 슈퍼-서브타입으로 만들어야할지 고민하고 있다.
우선, 관련된 레퍼런스를 보면서 공부를 해보자.
대출과 카드는 심사 내역은 분리됐지만, 연체 이후에는 통합된다
심사는 평가항목이 대출과 카드가 차이가 나서 하나로 통합하면 불리한 점이 많다.
연체 이후는 공통적인 항목이 많다. 법적 절차 테이블은 고객별 데이터라서 통합이 효율적이다.
(1)OneToOne 개별 테이블 방식
(2) 슈퍼+서브테이블
대출 기본에 공통 속성을 묶고 여신 대출 기본, 수신대출기본에 기본 속성을 넣는다.
(3) 통합 테이블
테이블명만 12개 --> 나중에는 200개가 넘을 수 있다. 어느정도 통합이 필요.
개별 속성을 조회할 때는 여러번의 조인이 발생함.
한개의 테이블로 -> 상이한 속성이 너무 많아서 현실적인 설계는 아니다.
해법은?
되도록 공통 분모를 묶는 것이다.
데이터 양이 적으면 성능상 이슈가 없기 때문에 되도록 통합하는 게 좋다.
데이터양이 많으면 슈퍼/서브테이블로 분리하는 게 좋다.
->트랜잭션을 분리해서 공통적인 속성 먼저 입력시키고, 개별적인 속성은 팝업으로 입력하도록 업무 변경을 유도할 수 있따.
상품, 금리, 수수료가 통합
고객정보는 고객에 통합돼 관리
우선, 로그는 위처럼 공통속성이 많다. 그리고, 개별속성이 적다.
있어봤자 이 정도다.
그런데, log를 볼 때는 이 테이블들을 모두 한번에 봐야할 때가 많다. join이 많아질 수밖에 없다.
하나의 테이블에서 관리하면 관리도 쉬워질 것이고, 한눈에 파악도 좋을 거이다.
또, 통합테이블로 해야 파티셔닝도 쉽다고 한다.
CREATE TABLE logs (
id BIGINT,
timestamp TIMESTAMP,
type VARCHAR(50),
user_id VARCHAR(100),
details JSONB,
-- 다른 필드들...
) PARTITION BY RANGE (timestamp);
-- 월별 파티션 생성
CREATE TABLE logs_202401
PARTITION OF logs
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
CREATE TABLE logs_202402
PARTITION OF logs
FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
통합 기반
==========================
-- 각 테이블별로 파티셔닝 필요
CREATE TABLE base_logs (
id BIGINT,
timestamp TIMESTAMP,
type VARCHAR(50)
) PARTITION BY RANGE (timestamp);
CREATE TABLE point_logs (
id BIGINT,
expiration_date TIMESTAMP,
FOREIGN KEY (id) REFERENCES base_logs(id)
) PARTITION BY RANGE (timestamp);
CREATE TABLE payment_logs (
id BIGINT,
amount DECIMAL,
FOREIGN KEY (id) REFERENCES base_logs(id)
) PARTITION BY RANGE (timestamp);
서브타입은 테이블별로 파티셔닝 필요
==========================
그래서, 로그는 우선 통합 테이블을 쓰면서 null값을 일부 허용하는 방식을 쓰기로 했다.
Database design - single subtype in a separate table vs common table
이 글에서는 일반 사람(유저) 테이블이 있고, 배달원 역할을 하는 사람의 테이블이 있다고 한다.
유저 테이블 하나를 두고 두개의 정보를 다 가져가느냐, 아니면 배달원을 서브타입 테이블로 빼느냐 이걸 고민하고 있다.
USERS:
id(PK)
email
password
name ...
driver_license_id (null for all regular users)
avg_rating (null for all regular users)
more delivery person specific columns
Option #2
USERS:
id(PK)
email
password
name
DELIVERY_PERSON:
id (PK, FK to USERS.id)
driver_license_id
avg_rating
more delivery person specific columns
I've seen several similar questions on SO, but in all of them there are multiple subtypes like Vehicle -> Car/Airplane/Boat etc.
확장 가능성이 크지는 않은데 굳이 이걸 서브타입으로 빼야 할지도 고민하는 것으로 보인다.
추가 정보를 자주 조회하지 않으면 분리, 항상 모든 정보가 필요하면 하나의 테이블로 한다.
캐시와 포인트는 항상 같이 조회돼야 한다.
하지만, 이걸 하나의 테이블로 만드는 건 위험해보였다.
우선, 캐시는 실제 현금이고 포인트는 무료 캐시다. 그만큼 캐시 관리가 더 엄격해야 한다고 생각한다.
두개를 같은 테이블에 넣고서 포인트는 업데이트가 매우 잦은데, 그 과정에서 캐시를 잘못 업데이트한다면? 포인트를 잘못 업데이트할 때보다 더 큰 책임을 져야 할 것이다. 두개의 도메인에 각각 다른 정책을 실시할거라면 두개를 분리하는 게 더 편할 거 같다.
매번 JOIN을 한번 하는 건 사실 조회시 큰 성능적인 차이는 없을 것이다.
두개의 테이블은 공통 칼럼이 많지도 않아서 서브타입으로 할 필요도 없어 보인다.
이 글을 보면 이런 경우에 유지 보수의 관점에서 슈퍼-서브 클래스를 쓸 수 있다고 한다.
공통된 칼럼이 여러개가 있다면, 이걸 여러군데에서 다 관리하는 것보다 하나의 공통 테이블에서 관리하는 게 더 편하다. 자바에서도 이런식으로 객체지향을 구현한다.
로그 관련 코드를 구현해보니
위 처럼 공통적으로 있어야 할 칼럼들이 있었다.
이걸 현금으로 구매한 Key와 무료로 받은 Key 테이블에 칼럼으로 두고 각각 관리하는 것보다 한 곳에서 관리하는 게 더 편할 것이다.
참고로, 무료로 받은 Key는 유효기간도 로그에 적어두어야 한다. 근데, 현금으로 구매한 키는 유효기간이라고 할 게 없다.
이런 경우 PointKeyLog 테이블만 만들어 놓고 저 슈퍼 테이블을 상속하게 할 수 있다.
@Inheritance는 이 클래스가 슈퍼클래스라는 알려준다. default는 SINGLE_TABLE이다.
(SINGLE_TABLE, // 통합 TABLE_PER_CLASS, // 분할 JOINED; // 혼합)
@DiscriminatorColumn는 자식 클래스를 구분 짓는 칼럼의 이름이다.
What are the benefits of super type sub type table-스택오버플로우
이러한 서브타입의 장점은 공통된 칼럼, 연관관계를 한 곳에서 관리한다는 것이다. 서브타입에서는 이 타입에 특화된 칼럼을 가질 수 있다.
이 모델링에선 모든 계좌 정보를 알려면 세개의 테이블을 각각 조회해야 한다. 또한, customer와 각각의 계좌가 연관관계를 가져야 한다. 또한, 쿼리들 역시 각 타입에 맞춰서 저장/조회를 해야 한다는 불편함도 생긴다.
Dealing with subtypes and supertypes in Database design
이 글을 보면 퍼포먼스가 중요하다. --> 핵심 칼럼들을 간소화하는 게 중요하고, 많이 쓰지 않은 칼럼을 메인 테이블에 두지 않는다.
코드의 간편함이 중요하다 -->약간의 null을 허용하고 성능저하를 감수
SQL Server의 Sparse Columns 기능--> NULL이 많은 컬럼을 효율적으로 저장할 수 있는 기능
90%가 "in-house"이고 10%만 "purchased"라면, purchased 관련 컬럼을 sparse column으로 지정하여 저장 공간 효율성 확보
비즈니스 요구사항에 따라 적절한 전략을 선택해야 함
절대적인 정답은 없으며, 구체적인 상황과 요구사항에 따라 결정해야 함
Implications of Supertype and Subtype
(1)PAGE와 USER 테이블이 각각 IMAGE와 직접 연결되는 구조
더 단순하고 직관적인 구조
(2)ENTITY라는 상위 테이블을 만들고 USER와 PAGE가 이를 상속
ENTITY_IMAGE 테이블을 통해 이미지 관계 관리
단순히 이미지 첨부 기능만 필요하다면 첫 번째 방식이 더 적합
향후 다양한 타입이 추가될 가능성이 있다면 두 번째 방식 고려
비즈니스 요구사항과 확장 가능성을 고려하여 선택해야 함
계속 이랬다 저랬다 하지만... 책을 보니 원래 이렇게 논리 모델을 먼저 만들어서 정규화를 하고
그 다음에 성능 개선을 위해서 통합하는 과정이 필요하다고 한다.
이 칼럼 하나만을 위해서 이 클래스를 서브타입으로 두고, JOIN을 하는 게 괜찮을까?
이렇게 계속 늘어나면 Join이 많아지면서 성능에 이슈가 생길 수밖에 없다.
영한샘은 실무에서도 많이 쓰지 않는다고 했다.