밍 석 2023. 12. 4. 08:40

📝느낀 점

프로젝트 ERD를 설계하며, 느낀 점을 작성해 보려고 합니다. (완성된 ERD 사진은 마지막에 있습니다)
기본적으로 백엔드 프로젝트라면 필수적인 DB가 있어야 합니다. 대부분 관계형 DB를 사용하기에 테이블 간에 관계에 대해 잘 생각해서 ERD를 설계해 보려고 합니다. 하지만, 비전공자로써 ERD를 처음 설계해 보려고 하니 막막함이 따랐습니다. 그런 부분들에 대해 밑에서 하나씩 풀어, 설명해 드리도록 하겠습니다.

 

 

MYSQL을 선택하게 된 이유는?

MYSQL은 관계형 데이터베이스 관리 시스템(RDBMS)으로 웹 애플리케이션에서 많이 사용되고 있습니다. 밑에 있는 사진처럼 상위권에 위치하는 만큼 안정성과 성능이 보장된다고 볼 수 있다고 생각하였고, 오픈 소스 및 라이센스 비용이 무료로 사용할 수 있기에 취준생(저)에게는 좋은 장점이 아닌가 싶습니다. 그리고 구글링을 통해 문제가 발생했을 시 여러 가지의 많은 자료들을 확인할 수 있다는 점, 마지막으로 성능 및 속도 면에서도 MYSQL은 빠른 처리 속도를 제공한다는 점입니다. 이런 점들을 전부 생각해 보면, 왜 기업에서나 회사에서 MYSQL을 사용하는지를 알 수 있지 않을까 생각이 듭니다.

확인할 수 있는 링크 :  https://db-engines.com/en/ranking_trend

 

 

1차) 처음부터 설계하다.

전부 작성하고 보아하니, 문제점이 한 개 두 개가 아녔습니다. 하하…

 

처음이라 그런가, ERD를 만들 때부터 끝 날까지 "아... 이거 맞아?" 하면서 의심에 의심을 하며 설계하게 되었습니다.

틀린 부분은 어디인지, 필요한 컬럼은 다 넣은 것이 맞는지, 테이블을 나눈다고 나눴는데 확실한 건지, 테이블이 점점 생겨나는 게 맞는 것인지, 감이 오지 않았기에, 일단 전체적인 틀은 작성하자는 마음으로 필수적인 테이블들을 설계하기 시작했습니다. 그렇게 하여 처음으로 설계된 테이블 전체 구조입니다. 이제부터 문제점들에 대해 하나씩 설명하며 진행하도록 하겠습니다.

 

첫 번째 문제.

첫 번째 문제. snake_case 또는 camelCase 하나로 통일해야 하는데 뒤죽박죽이라는 점입니다.

통일해야 되는 이유는, 개발은 혼자 하는 것이 아닌 여러 사람과 개발하기에 명명 규칙을 따른다면, 코드의 가독성과 유지보수에 있어서 큰 도움일 수 있다고 생각하기 때문입니다. 데이터베이스는 주로 snake_case 사용한다고 알고 있지만, 회사 또는 팀마다 다르다는 글을 봤습니다. 이건 회사에 맞게 개발을 진행하면 되지 않을까 생각이 듭니다.

일단 저는 snake_case 인 언더스코어(_)를 사용하는 방식으로 진행하였습니다!

 

두 번째 문제.

두 번째 문제. 긴 글이 사용될 경우 text타입을 사용하지 않고 varchar 타입을 사용하였다는 것입니다.

둘 다, 문자열 데이터를 저장하는 데 사용되는 데이터 타입입니다. 여기서 무엇을 선택하냐의 차이는 저장 용량에 따라선택 기준이 변경된다는 점입니다. 즉, varchar 타입 같은 경우는 최대 길이 255만큼을 넘어, 최대 길이를 유저가 명시해 주는 방법으로도 적용할 수 있으나, text 타입 같은 경우는 최대 길이의 제한이 없습니다. 그렇기에 우리가 게시판에 사용되는 본문에 사용되는 것이 바로 text입니다. 그렇기에 사용자가 원하는 만큼 작성하여도, 문제가 발생하지 않도록 제한이 없는 test 타입을 사용하는 것이 좋은 선택이라고 생각합니다.그리고 varchar와 text는 둘 다 가변 길이라는 점입니다.

 

세 번째 문제.

세 번째 문제. 운영에 필수적인 컬럼들을 작성하지 않았다는 것입니다. (위 사진에는 추가되어 있습니다)
created_at, created_by, modified_at, modified_by는 운영에 필수적인 컬럼들입니다. 시간은 UTC 기준으로 DB에 저장하면 편리함이 있으며, 프론트 엔드화면에서 해당 시간을 타임존을 적용해서 보여주면, 사용자에게는 로컬 시간으로 보인다는 것입니다. 그렇기에 사용하게 된다면 좋은 점이 많기에, 많이 사용하는 필수 방식인 것 같습니다

 

네 번째 문제.

네 번째 문제. 이미지 타입을 mediumblob을 사용하였다는 점입니다.

이미지를 저장하려면, 대용량의 데이터를 저장하는 특성이 있어야 하는데, "과연 이런 방법이 좋은 것일까?" 의문점이

들기 시작했습니다. 왜냐하면 이렇게 사용할 경우 "데이터베이스 성능에 부하가 오진 않을까?" 생각하여 구글링 하여

봤더니, 역시나! 이미지, 비디오 같은 대용량 파일을 저장하는 경우 데이터베이스의 백엔드 네트워크에서 처리해야 할

작업이 늘어나 성능 저하가 발생할 수 있다는 글을 보게 되었습니다.

 

그렇기에 이, 해결책을 찾기 위해 검색한 결과 S3에 이미지를 저장 후 S3의 URL을 데이터베이스에 저장한다는 방식이

있었습니다. 대박...! S3를 사용했을 때의 장점으로는 대용량의 데이터를 데이터베이스에 저장시키지 않기에 성능 부하를 줄일 수 있다는 장점이 있을 수 있겠으며, 로딩 속도, 데이터베이스를 최적화할 수 있다고 생각하였기에 이미지 타입을

text로 변경하였습니다.

 

 

2차) 위 문제점들을 바탕으로 개선한 ERD입니다.

지금 이 글을 작성하는 시점에서 다시 보아하니 문제가 많아 보인다 ㅎ…

 

이렇게 완벽하지 않은 테이블을 올리고 하려니,, 부끄럽지만 이 글을 통해 다시 한번 생각이 정리되고,

왜 저렇게 생각했었는지에 대한 틀린 점과 개선을 생각함으로써 앞으로는 이런 실수를 두 번 다시 하지 않게 될 것입니다.

 

 

첫 번째 문제.

첫 번째 문제. 게시판 테이블, 사용자 피드 테이블들이 너무 많은 책임을 가지고 있다는 것입니다

문득, 변경 전 게시판을 보고 있으니 컬럼이 너무 많다는 생각을 하게 되었으며, “단일 책임 원칙”을 따르지 않았다는 생각을 하게 되었습니다. 그리고 무엇보다 테이블에서 보고 있으니, 너무 복잡해 보인다는 생각을 하였고, 관계형 데이터베이스를 사용하는 이유가 무엇일까?라는 고민을 하게 되었습니다.

 

그렇기에, 관계형 데이터베이스를 사용하는 만큼 테이블을 분리하기로 하였습니다.

그리하여 게시판 테이블에서의 좋아요, 조회수 같은 상태를 표시하는 칼럼들은 article_status 테이블을 생성하여 분리해 줬습니다. article_status에 필요한 애들은 무엇일까? 고민하던 결과, “댓글 또한 상태 테이블에 들어가야 하는 게 아닐까?” 생각이 들어 article_comment 테이블을 삭제시키고 article_status에 댓글까지 추가하게 되었습니다 ㅎ... 뭐하냐

article 테이블이 하는 일이 많다고 판단되어 분리했는데, 이번엔 article_status 가 많은 역할을 참고하게 되었네요 하하…. 그리하여 나중에는 다시 article_comment 테이블을 만들어 책임을 분리했습니다.

 

두 번째 문제.

두 번째 문제. 필요 없는 연관 관계 컬럼들입니다. article_status 테이블은 article_id라는 참조 컬럼을 가지고 있습니다.

그렇다는 말은 article_id를 통해 article 테이블을 참조할 수 있으며, article 테이블에는 member를 확인할 수 있는 memer_id 컬럼이 존재하고 있는데, 굳이 article_status 테이블에 member_id 컬럼이 필요할까? 고민하였고, 이 부분이 잘못되었다고 판단하고, 컬럼들을 삭제하였습니다.

 

세 번째 문제.

세 번째 문제. member 테이블의 member_id 네이밍 변경입니다.

pk가 아닌, 사용자가 로그인할 때 작성하는 아이디를 member_id 네이밍으로 작성하였는데, 다른 테이블에서 member 테이블을 참조할 때의 컬럼들 이름들이 member_id 이기에 혼동이 올 수 있다는 점에서 member 테이블에서의 컬럼명을 member_id에서 → name으로 수정하였다는 점입니다. 이렇게 혼동이 되는 내용들은 나만 알고 있기에, 협업을 하게 될 경우 오해를 살 수 있다고 생각 듭니다. 그렇기에 이런 작은 부분들도 주의해야 한다고 생각합니다.

 

네 번째 문제.

네 번째 문제. 테이블 간의 관계가 너무 많다는 것입니다. article 에는 여러 comment가 작성될 수 있는데, A라는 article의 댓글 10개를 가져오려면 테이블 조회가 어떻게 이뤄져야 하는가? 천천히 생각을 해보는 것이다. article과 comment의 관계는? -> 1:N 관계(article 1개당 comment 여러 개)입니다. 그렇다면, comment는 article 테이블을 참조해야 하겠다고 생각하게 됩니다. 그렇게 되면, comment 테이블에 article_id를 넣자는 결론이 나오게 됩니다.

 

또한 profile 테이블은 member의 프로필 정보를 나타내는 테이블이기에 특정 member에 매핑될 것입니다.

그렇기에 이건 1 : 1 관계가 되는 것이고, profile 테이블에서 member 테이블을 가리키면 되겠다고 판단할 수 있습니다.

천천히 다시 생각해 보면 충분히 할 수 있는 것인데, 뭐가 그리 급하다고 빨리빨리 하는 생각에 더 엉망이 되어 버린 것 

같습니다. 앞으로는 하나를 하더라도 천천히 해야겠다고 생각하게 되었습니다.

 

 

3차) 위 문제점들을 바탕으로 개선한 ERD 입니다.

 

어느 정도 ERD 설계는 끝났다고 생각하였지만, 기능 구현을 하면서도 문제점이 하나씩 보였습니다 ㅎ... 이런 문제점들에 대해서도 하나하나 기록하는 것 또한 공부라고 생각합니다. 글을 작성함으로써 머릿속으로 리마인드가 한번 더 되었기 때문입니다. 이처럼 프로그램을 개발하기 전까지는 생각도 못해본 문제사항들을 마주치면서 “진짜” 지식이 되는 것 같습니다. 그렇기에 지금 프로젝트가 끝난 뒤에도 작은 프로그램을 만들면서 실전 감각을 키워야겠다고 생각했습니다.

 

문제.

문제. 현재 구조에서는 한 명의 유저가 특정 게시판에 좋아요를 무한정 높일 수 있는 구조라는 것입니다.

유저 1명이 아닌, 10명? 그 이상이라면? 정말 생각지도 못했던 문제였습니다. 이 부분을 어떻게 하면 특정 유저의 좋아요 수를 제한할 수 있을까? 고민을 하였는데, article_status 테이블에서 사용자가 눌렀는지?, 누르지 않았는지? 판단하는 칼럼을 하나 추가하면 어떨까 생각하여 봤습니다.

 

사용자가 눌렀는지 확인할 수 있는 컬럼을 하나 추가한다면, 애플리케이션 단에서, 추가한 컬럼을 조회하여 if() 문을 통해 현재 값이 1이라면 "감소" 시켜 좋아요를 누르기 전 상태로 변경하는 것은 어떨까 생각하여 봤으나, 이 방법으로는 해결이 되지 않습니다. 그 이유로는 "article 테이블에 있는 member_id를 사용하면 되잖아?" 하는 생각부터 잘못 잡고 있어서 이런 실수를 하였다고 생각합니다. 게시판에서의 member_id는 게시판을 작성한 유저인데 말입니다 ㅎ.. 제가 찾아야 할 유저는 해당 게시판에 좋아요를 누른 사람이라는 것입니다. 바보야. 

 

그리하여 곰곰이 생각해 본 결과 현재, article 테이블, article_comment 테이블, article_status 테이블들로 나눠져 있는 구조인데, 좋아요 테이블도 분리하면 어떨까?라는 생각을 하게 되었고, 이 해결책이 정답이 될 수 있겠다는 생각을 하며 테스트를 해본 결과, 문제를 해결할 수 있었습니다. 그 이유는 새로 추가한 article_likes 테이블을 만들어 줌으로써 유저가 어떤 게시판에 좋아요를 눌렀는지 확인이 가능하게 되었기 때문입니다.

 

또한 이 부분을 해결하면서 고민이 생겼습니다. "article_status 테이블에 좋아요 수를 나타내는 컬럼이 없다면??", "해당 게시물을 조회할 때 article_likes 테이블에 저장된 칼럼으로만 찾는다면??" 이런 고민들을 하게 되었습니다. 그 결과, 해당 게시물을 조회할 때마다 article_likes 테이블에 저장된 해당 게시물을 좋아요 한 row를 모두 조회해야 한다는 단점이 생긴다는 것 입니다. 이렇게 될 경우 성능상으로도 단점이 될 수도 있겠다고 생각하였습니다.

select count(*)
from article_likes 
where member_id = 123

article_likes를 매번 조회한다면? 해당하는 데이터가 10만건이라면... 상상도 하기 싫다..

 

처음에는 막막하고 복잡하다 생각 들었지만, 천천히 해보고 공부하고 하니 조금씩 알게 되며, 다음에는 더 잘할 수 있겠다는 자신감도 생겨났습니다. 앞으로는 작성한 이 글을 통해서 실수를 반복하지 않도록 하겠습니다. 그리고 기능을 구현하면서 테이블을 수정해야 할 부분이 생겨나지 않을까 생각이 듭니다.

 

 

마지막

이러한 변경 사항들은 실제 운영 환경에서 발생할 수 있는 다양한 상황을 고려하여 설계 했습니다. 처음에는 단순한 구조였지만, 프로젝트를 진행하면서 다양한 요구사항과 시나리오를 반영하여 설계를 보완할 수 있었습니다. 이로 인해 데이터베이스의 확장성과 유지보수성이 크게 향상되었습니다. 이번 프로젝트를 통해 얻은 가장 큰 교훈은 설계 초기 단계에서부터 가능한 다양한 상황을 고려하는 것이 중요하다는 점입니다. 앞으로도 이러한 경험을 바탕으로 더 나은 데이터베이스 설계를 위해 끊임없이 노력할 것입니다. 이 글을 통해 ERD 설계 과정에서의 경험을 공유드립니다!