사용자가 어떤 컨텐츠에 대해 bookmark
또는 pass
를 할 수 있다고 하자.
어떤게 적절한 스키마가 될 수 있을까?
기존에 User
스키마와 Contents
스키마가 있다고 하자. (sql은 작성 편의상 네이밍, 문법 등은 고려하지 않았다.)
CREATE TABLE contentStatus (
id INT AUTO_INCREMENT,
user_id INT,
content_id INT,
bookmark bool,
pass bool,
PRIMARY KEY(id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (content_id) REFERENCES contents(id)
);
CREATE TABLE contentStatus (
id INT AUTO_INCREMENT,
user_id INT,
content_id INT,
status ENUM(bookmark,pass,...etc),
PRIMARY KEY(id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (content_id) REFERENCES contents(id)
);
CREATE TABLE bookmarks (
id INT AUTO_INCREMENT,
user_id INT,
content_id INT,
PRIMARY KEY(id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (content_id) REFERENCES contents(id)
);
CREATE TABLE passes (
id INT AUTO_INCREMENT,
user_id INT,
content_id INT,
PRIMARY KEY(id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (content_id) REFERENCES contents(id)
);
1안의 경우 bool로 관리되므로, 상태 확인 및 업데이트가 명확하고 직관적인 편이다. 쿼리 역시 단순하게 작성할 수 있다. 반면, 상태가 추가될 때마다 새로운 칼럼이 필요해져 테이블이 커질 수 있다.
2안의 경우, Enum 하나로 모든 상태를 관리할 수 있어 테이블 구조가 단순해진다. 또한 새로운 상태가 추가되더라도, Enum에 새로운 값을 추가하면 되므로 확장성이 좋다. 하지만, 엔티티 는 동시에 여러 개의 상태를 가질 수 없게 된다. 운영체제 프로세스 상태 천이나 로그인 상태 등 동시에 여러 개의 상태가 존재해서는 안될 경우에 적합한 설계다.
3안의 경우, 기획 변경에 대한 확장성이 좋으며 하나의 엔티티가 여러 개의 상태를 가질 수 있는 설계다. 하지만 테이블이 하나 더 생기므로 join 연산이 하나 더 추가된다. 뿐만 아니라 여러 개의 상태를 가질 때 공존할 수 없는 상태의 경우에는 어플리케이션 레벨에서 잘 관리해야 한다. 추후 사양 변경이나 기획 요구 사항 변경으로 확장성을 충족시켜야 할 때, 특히 추후 동시에 여러 개의 상태가 존재하게 될 수도 있다고 판단되는 경우 적합한 설계다.