오랜만에 포스팅을 하는데.. 계속 다짐을 하지만 천천히라도 정리한 글을 올릴 예정입니다.. ㅠㅠ
해당 포스팅은 Instagram의 피드에 대한 DB 스키마 디자인을 생각해 보고 정리한 글입니다.
DB 스키마 디자인을 실습한 사이트는 이곳입니다.
인스타그램 피드
인스타그램의 피드는 위 이미지와 같은 형태로 올릴 수 있습니다. (위 피드는 제 계정인데.. 활동을 안 합니다)
해당 이미지로 피드의 기능들을 분류해 보면 다음과 같이 분류가 가능합니다.
- 여러 장의 사진 업로드
- 본문
- 댓글
- 게시글에 대한 좋아요 및 댓글에 대한 좋아요
- 태그 (해당 이미지에는 보이지 않지만.. 인스타그램의 "#태그"를 의미합니다)
대강 이 정도의 기능으로 분류가 가능하며, 인스타그램의 시스템 중 계정 팔로우, 팔로워 기능도 존재합니다.
그렇다면 인스타그램에서는 이 기능들에 대한 서비스를 제공하기 위해서 데이터를 DB에 저장하고 관리해야 할 텐데 어떤 식으로 테이블을 구성하여 했을지 생각해 보며 스키마를 디자인해 보았습니다.
인스타그램 스키마 디자인
위 이미지와 같이 스키마를 디자인해 보았습니다. 위 이미지를 왼쪽에서 우측으로봐주시면 될 것 같습니다.
해당 스키마 디자인을 할 때 큰 틀만 생각하면서 디자인을 했다 보니 user 테이블의 사용자 이름, 계정, 생년월일 등의 칼럼도 필요하지만 생략하였습니다.
그럼 이제 위 이미지처럼 디자인을 한 이유에 대해 설명을 해보겠습니다.
일단 모든 테이블에는 해당 칼럼들을 식별할 수 있는 primary key를 id라는 칼럼명을 사용하는 int 타입 및 auto_increment로 지정하기로 하여서 모든 테이블에는 id 칼럼이 존재합니다.
이후 어떻게 설계를 할까 고민을 하다 보니 1:1 매칭인 내용들은 하나의 테이블에 칼럼으로 모아두고, 1:N 매칭이나 N:M 매칭인 항목들은 각각의 성격에 맞는 테이블로 나누어 설계를 해야 할 것 같다고 생각하였습니다.
여기서 매칭되는 값들을 각각의 테이블의 primary key와 foreign key로 설정하여 원하는 값을 join 하여 찾는다고 생각하고 디자인을 시작하였습니다.
디자인 설명
위에서의 생각 정리가 끝난 후 일단 id 값만을 갖는 user 테이블을 만들어 둔 후 post 테이블의 설계를 생각하기 시작하였으며, 아래와 같은 생각을 하며 설계를 진행하였습니다.
- 해당 post는 누가 쓴 글인가?
- user table의 id를 foreign key로 하는 칼럼을 만들어서 join 하여 찾을 수 있다고 생각 => userId 칼럼 생성
- 사진은 무엇이 등록되어 있는지?
- 여러 장의 사진이 등록될 수 있는데, 몇 장의 사진이 업로드 가능한지 제한이 없다면?
- 칼럼에 계속적으로 데이터를 추가하여 저장하기에는 사이즈 설정에 문제 발생
- 따라서 새로운 테이블을 만들고, 해당 테이블에서 post의 id를 foreign key로 하여 관리해야겠다고 생각 => photo 테이블 생성
- 추가로 photo 테이블에는 이미지 저장 경로를 기록해 둘 image 칼럼 추가
- 본문의 내용엔 무엇이 있는지?
- 본문에 작성하는 글을 저장한 body 칼럼 생성
- 글을 저장하기 때문에 varchar 타입으로 지정하였으며, size는 임의로 255 할당
- 언제 생성이 되었는지?
- timestamp 타입을 저장하는 created_at 칼럼 생성
- 데이터가 기록된 시간을 자동으로 받도록 "DEFAULT CURRENT_TIMESTAMP" 옵션 적용
- 해당 글에 태그는 있는지?
- 사진 등록과 같은 이유로 하나의 피드에 여러 개의 태그가 있을 수 있으며, N:M 관계가 된다.
- 따라서 1:N, M:1 관계로 바꿔주기 위해서 tag 테이블 생성 후 post_tag 테이블을 만들어 사용
- 해당 글에는 어떤 댓글이 달려있는가?
- 피드에 여러 개의 댓글이 달릴 수 있으므로 1:N 관계 => comment 테이블 생성
- 이후 post의 id 값을 foreign key로 갖는 postId 칼럼을 추가
- 그리고 누가 작성한 댓글인지 알 기 위한 user의 id 값을 foreign key로 갖는 userId 칼럼 추가
- 댓글의 내용을 저장할 varchar 타입의 body 칼럼 추가
- 댓글의 생성 시간을 알 수 있도록 timestamp 타입을 저장하는 created_at 칼럼 추가
- created_at 칼럼은 post 테이블의 created_at 칼럼과 동일하게 "DEFAULT CURRENT_TIMESTAMP" 옵션 적용
- 해당 글에는 누가 좋아요를 했는가?
- 하나의 피드에 여러 명의 사람이 좋아요를 누를 수 있기 때문에 1:N 관계 => like 테이블 생성
- 어떤 피드에 좋아요를 눌렀는지 알 수 있어야 하므로, post 테이블의 id 값을 foreign key로 갖는 postId 칼럼 추가
- 누가 해당 피드에 좋아요를 눌렀는지 알 수 있어야 하므로, user 테이블의 id 값을 foreign key로 갖는 userId 칼럼 추가
- 좋아요를 누른 시간은 굳이 저장할 필요가 없다고 생각되어 created_at 칼럼은 생략
- 팔로워와 팔로우를 어떻게 관리해야 하는가?
- user 테이블의 id를 기준으로 누가 누구를 팔로우 하는지만 알면 역으로 팔로워도 계산이 가능하다고 생각
- 따라서 누가 누구를 팔로우 하는지에 대한 데이터만 갖고 있으면 된다고 생각
- 팔로우의 경우 1명이 여러 명을 할 수 있는 1:N 관계이므로 follow 테이블 생성
- 누가, 누구를 팔로우 하는지를 기록하는 followerId와 followingId 칼럼을 추가
- 해당 칼럼들은 user의 id를 foreign key로 갖는 칼럼 (user가 user를 팔로우하기 때문)
마치며
실제 서비스상에서 DB를 구축하여 사용한 경험이 없는 상태에서 생각해 보고 만들어 본 내용이기 때문에 위 설명들 및 테이블, 칼럼 등에 비효율적이거나 불필요한 내용이 있을 수 있습니다!
일단 제가 찾아본 결과 사진을 관리하는 부분에서 blob(binary large object) 타입을 이용하거나, 다른 방식을 이용해서 관리하는 경우가 있다는 내용을 본 것 같으나.. 실제 적용하여 테스트를 하는 과정은 아니고 대략적인 디자인만 하던 것이라서 이런 게 있구나.. 하고 넘어갔습니다.
이러한 부분이나 위 내용에서 수정이 필요한 부분, 개선점 등이 있다면 댓글로 알려주시면 반영을 하도록 하겠습니다!
혹시나 https://dbdiagram.io 사이트에서 위 관계도를 직접 보고 싶으신 분이 계실지 몰라서 위 내용을 작성한 MySQL을 공유드립니다.
해당 사이트에서 "Create your diagram" 클릭 > "Import" 클릭 > "Import from MySQL" 클릭 후 아래의 내용을 넣으시고 "Submit" 버튼을 눌러주시면 됩니다.
CREATE TABLE user (
id int PRIMARY KEY AUTO_INCREMENT,
);
CREATE TABLE tag (
id int PRIMARY KEY AUTO_INCREMENT,
title varchar(255) NOT NULL
);
CREATE TABLE post (
id int PRIMARY KEY AUTO_INCREMENT,
userId int,
body varchar(255),
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (userId) REFERENCES user(id)
);
CREATE TABLE post_tag (
id int PRIMARY KEY AUTO_INCREMENT,
tagId int,
postId int,
FOREIGN KEY (tagId) REFERENCES tag(id),
FOREIGN KEY (postId) REFERENCES post(id)
);
CREATE TABLE comment (
id int PRIMARY KEY AUTO_INCREMENT,
postId int,
userId int,
body varchar(255) NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (postId) REFERENCES post(id),
FOREIGN KEY (userId) REFERENCES user(id)
);
CREATE TABLE like (
id int PRIMARY KEY AUTO_INCREMENT,
postId int,
userId int,
FOREIGN KEY (postId) REFERENCES post(id),
FOREIGN KEY (userId) REFERENCES user(id)
);
CREATE TABLE photo (
id int PRIMARY KEY AUTO_INCREMENT,
postId int,
image varchar(255) NOT NULL,
FOREIGN KEY (postId) REFERENCES post(id)
);
CREATE TABLE follow (
id int PRIMARY KEY AUTO_INCREMENT,
followerId int,
followingId int,
FOREIGN KEY (followerId) REFERENCES user(id),
FOREIGN KEY (followingId) REFERENCES user(id)
);
'Develop > TIL(Today I Learned)' 카테고리의 다른 글
SpringBoot 기준 log 정리 (0) | 2023.02.02 |
---|---|
SpringMVC DispatcherServlet 동작 방식 (0) | 2023.02.02 |
[2022.05.24] 자료구조/알고리즘 - 재귀 (0) | 2022.07.25 |
[2022.05.23] 모의 기술 면접 (0) | 2022.07.25 |
[2022.05.13] OOP 심화 2/2 - 다형화, 추상화 (0) | 2022.07.25 |