[DB 설계] 데이터베이스 모델링(Database Modeling) - 중복을 찾아 정규화 하기

iiingkeep·2024년 12월 3일

Database

목록 보기
17/21

정규화의 핵심

정규화의 핵심은 중복 제거이다.

한 테이블에서 중복된 데이터가 많이 나온다면 이후에 수정같은 작업을 해야할 때 모든 행에서 같은 데이터를 일일이 찾아 작업해야 한다. 이런 과정은 이후에 이상 현상을 일으킬 수 있다. 이를 방지하기 위해 중복 데이터가 발생할지 미리 예측하고, 테이블을 분리해놓는 작업이 필요하다.

중복 데이터를 찾아 정규화 하기

모델링을 할 때 테이블을 만들었다고 가정하고 데이터를 넣어 시뮬레이션 해 본다.
예를 들어 커뮤니티 사이트의 게시글 테이블을 만든다고 가정하자.

중복 데이터 찾기

아래의 게시글 테이블을 보면 작성자에 짱구가 중복으로 여러 번 등장하는 것을 볼 수 있다. 만약 짱구의 이름을 맹구로 바꾼다면 세 개의 짱구를 맹구로 수정해줘야 한다. 지금은 세 개지만 만약 이런 데이터가 몇 백, 몇 천개라면 작업을 하는데 시간도 오래 걸리고, 실수가 발생할 수 있어 비효율적이다.

posts Table

id제목내용작성자
1안녕하세요반갑습니다짱구
2오랜만입니다시험 끝나고 왔습니다짱구
3요즘 날씨좋죠???짱구

정규화 하기

이 때 작성자를 다른 테이블로 분리한 뒤 Foreign key로 가져오면 이 문제는 해결된다. Foreign key로 데이터를 가져올 경우 중복되는 데이터(작성자 id) 1은 중복으로 치지 않는다.

posts Table

id제목내용작성자 id(FK)
1안녕하세요반갑습니다1
2오랜만입니다시험 끝나고 왔습니다1
3요즘 날씨좋죠???1

users Table

id제목
1짱구

위와 같이 정규화를 마칠 경우 짱구의 이름을 맹구로 바꿔야 한다면 users Table의 짱구 데이터를 맹구로 변경해주면 된다. 한 번의 수정으로 끝나는 것이다.
시간도 단축되고 실수가 발생할 확률이 거의 없어진다.

진짜 중복 vs 가짜 중복

그렇다면 아래와 같은 테이블이 있다고 하자.
제목, 내용, 작성자의 데이터가 모두 중복되고 있다.

posts Table

id제목내용작성자
1안녕하세요반갑습니다짱구
2안녕하세요반갑습니다짱구
3안녕하세요반갑습니다짱구

하지만 사실 위에서 '진짜 중복'된 데이터는 작성자 데이터인 짱구 뿐이다.
작성자는 다른 테이블로 분리해야 하지만 제목과 내용은 그렇지 않다.
이 때 제목과 내용 데이터를 '가짜 중복' 이라고 표현한다.

진짜 중복 찾기

테이블을 제대로 분리하려면 진짜 중복과 가짜 중복을 가려낼 수 있어야 한다.
이 때 다음과 같이 질문해본다.

중복된 데이터 중 하나가 변경되면 나머지의 데이터도 변경해야 하는가?

  • 진짜 중복
    위의 게시글 테이블에서 작성자인 짱구가 맹구로 닉네임을 바꾼다고 가정해보자.
    한 명의 작성자인 짱구가 게시글 3개를 모두 작성했으므로 각각의 게시물 작성자를 모두 맹구로 바뀌어야한다.

  • 가짜 중복
    짱구가 작성한 3개의 게시글은 각각의 제목과 내용을 가진다. 작성자와는 다르게 하나의 게시글에서 제목과 내용 데이터를 변경하면 해당 게시글의 제목과 내용만 변경될 뿐, 다른 게시글의 제목과 내용에는 영향을 미치지 않고 독립적이다.
    게시글의 제목과 내용이 중복되는 것은 그저 우연의 일치일 뿐, 정규화 작업 대상이 되지 않는다.

이렇게 미리 시뮬레이션을 돌려보며 컬럼의 데이터들이 독립적인지 아닌지 구분해내면 진짜 중복을 찾을 수 있다.


다른 예시 )
각각 자신의 시그니처 밤양갱을 판매하는 세 가게가 입점한 온라인 쇼핑몰의 데이터베이스를 구축한다고 가정할 때, 아래와 같은 테이블이 있고 상품명 카테고리에 중복이 있는 것을 확인할 수 있다.

stores Table

id가게명상품명카테고리
1달코미밤양갱식품
2행복한먹거리밤양갱식품
3스낵월드밤양갱식품

진짜 중복 찾기

진짜 중복을 찾기 위해 시뮬레이션을 돌려본다.

  • 진짜 중복
    카테고리의 경우 '식품'이 중복되는데, 만약 이 '식품'을 '푸드'라는 이름으로 바꾼다고 가정 해 보자. 위의 밤양갱은 모두 식품 카테고리에 속하므로 식품의 카테고리 이름이 푸드로 바뀐다면 세 개의 카테고리를 모두 '푸드'로 바꿔줘야 할 것이다. 그러므로 카테고리 컬럼의 데이터에 중복이 있을 경우 진짜 중복이라고 할 수 있다.

  • 가짜 중복
    상품명의 경우 '밤양갱'이 중복된다. 만약 달코미 가게에서 상품명 '달디단 밤양갱' 으로 바꾼다고 가정 해 보자. 이 밤양갱 상품은 달코미의 시그니처 밤양갱으로, 다른 가게의 밤양갱과는 독립된 개체이다. 그러므로 다른 가게의 밤양갱 상품명이 같이 바뀌면 안 되고 달코미의 밤양갱만 바꿔줘야 한다. 그러므로 상품명 컬럼의 데이터는 중복이 있더라도 가짜 중복이라고 할 수 있다.

정규화

위에서 도출된 결과에 따라 테이블을 분리한 뒤 Foreign key를 넣어준다.

stores Table

id가게명상품명카테고리 id (FK)
1달코미밤양갱1
2행복한먹거리밤양갱1
3스낵월드밤양갱1

categories Table

id카테고리
1식품

숨어있는 중복 찾기

마지막으로 숨어있는 중복을 찾아 정규화 한다.

예시)
아래에 게시글, 사용자, 좋아요 테이블이 있다.
짱구와 철수가 1번 게시글에 모두 좋아요를 클릭해 좋아요 수는 2이다.

posts Table

id제목내용좋아요 수사용자 id(FK)
1안녕하세요반갑습니다21

users Table

id제목
1짱구
2철수

likes Table

id사용자 id게시글 id
111
221

얼핏 보면 별 문제가 없어 보이지만 이런 경우를 생각해 보자.
철수가 클릭했던 좋아요를 다시 클릭해 해제할 경우, 좋아요 테이블에서는 2번째 행이 삭제 될 것이다. 그럼 게시글 테이블에서도 좋아요 수가 2에서 1로 바뀌어야 한다. 이렇게 어떤 데이터를 변경할 시 다른 데이터도 변경해야 하는 경우 숨은 중복이라고 표현하겠다.
이 때 위에 언급했던 질문을 다시 상기해 보자.

중복된 데이터 중 하나가 변경되면 나머지의 데이터도 변경해야 하는가?

이 예시에서는 중복된 데이터는 아니지만, 어떤 데이터를 변경할 시 다른 데이터도 변경해야 하는 경우이므로 같은 경우로 생각한다.
좋아요 테이블에서 2번째 행이 삭제되더라도 게시글 테이블에서 변경된 좋아요 수가 반영되지 않는 현상이 일어날 수 있기 때문이다.
보통 이런 숨은 중복은 합계, 평균과 같은 통계 데이터에 해당한다.

정규화

'좋아요 수' 컬럼을 삭제해 다음과 같이 정규화 한다.

posts Table

id제목내용사용자 id(FK)
1안녕하세요반갑습니다1

users Table

id제목
1짱구
2철수

likes Table

id사용자 id게시글 id
111
221

좋아요 수와 같은 통계 데이터는 테이블로 표현하지 않는 대신, 좋아요 테이블에서 게시글 id가 x인 데이터의 갯수를 구하는 쿼리문으로 구해주면 된다.

SELECT COUNT(*) 
FROM likes 
WHERE 게시글_id = 1;



참고

이 게시글은 박재성님의 비전공자도 이해할 수 있는 DB 설계 입문/실전 강의를 토대로 작성되었습니다.
https://www.inflearn.com/course/%EB%B9%84%EC%A0%84%EA%B3%B5%EC%9E%90-db-%EC%84%A4%EA%B3%84-%EC%9E%85%EB%AC%B8/dashboard

profile
혁신적인 백엔드 개발자가 되고자, 기록✏️

0개의 댓글