...
정규화란?
ERD내에서 중복요소를 찾아 제거해 나가는 과정
- 중복된 데이터는 많은 문제를 일으킨다.
3차 정규화 정도만 알면 설계하는데 무리가 없다.
- 중복을 최소화 -> 완전히 없애는게 아니라 어느정도는 인정하겠다
- 시간을 줄이기 위해 (데이터베이스 안에 1억개의 튜플이 들어있다고생각해봐라)
몇가지 원칙만 지키면 정규화가 필요 없는 ERD를 설계할 수 있다.
데이터베이스 정규화 절차
함수 종속성을 이용해 릴레이션을 연관성이 있는 속성들로만 구성되 도록 분해해서 이상현상이 발생하지 않도록 Step By Step Approach 로 수행
기본 정규형으로는 제 1‧2‧3‧보이스/코드 정규형이 있으며, 제 4‧5 정규형 은 고급 정규형으로 분류
제 1 정규화
-> 제1차 정규화는 같은 성격과 내용의 컬럼이 연속적으로 나타나는 컬럼이 존재할 때, 해당 컬럼을 제거하고 기본테이블의 PK를 추가해 새로운 테이블을 생성하고, 기존의 테이블과 1:N 관계를 형성하는 것이다.
tag필드를 보면, 값들이 여러개가 있다. 하나의 필드에 값들이 여러개 있으면 안된다.
이를 정규화 시키보자.
1. 우선 하나의 title은 여러개의 tag를 같는다. 또한 하나의 tag(rdb)는 여러개의 title(mySQL, Oracle)을 같는다.
2. 그러면 title과 tag를 테이블 두개로 분리했을때 이들의 관계는 M:N이 된다.
3. M:N을 표현하기 위해선 테이블 3개를 만들어야 한다.
4. title과 topic테이블을 분단시키고 그 중간경로 테이블인 topic_tag_relation을 만든다. 그리고 각 테이블을 이어울 새로운 태그 tag_id속성을 만든다.
5. 그리고 각각 1:N 관계를 연결해주면 정규화가 완료한 것이다.
제 2정규화
-> 제2정규화는 PK가 여러 키로 구성된 복합키(Composite Primary Key)로 구성된 경우가 2차 정규화의 대상이 되며, 복합키 전체에 의존하지 않고 복합키의 일부분에만 종속되는 속성들이 존재할 경우 (즉, 부분적 함수 종속 관계) 이를 분리하는 것이다.
1. 제 1정규화를 마친 테이블을 보면, 중복되는 레코드(적갈색)가 보인다.
2. 저 부분이 중복되어 나타나는 이유는 type와 price 필드 값이 각기 다르기 때문이다.
3. 그러면 각기 다른 부분을 테이블로 나누고 중복부분을 하나로 표현되게 해보자.
4. 먼저 중복이 나타나게 한 원인 필드인 type와 price 필드를 따로 빼서 topic_type테이블을 만든다.
5. 그리고 topic_type에서 식별할수있는 외래키 title을 등록해준다.
6. 이렇게 하면, 중복되는 것 없이 title이 mySQL이냐 아니냐에 따라 topic 테이블에선 저자정보, topic_type테이블에선 가격과 타입을 각각 나타낼수있게 된다.
제 3정규화
-> 테이블의 키가 아닌 컬럼들은 기본키에 의존해야 하는데 겉으로는 그런 것처럼 보이지만 실제로는 기본키가 아닌 다른 일반 컬럼에 의존하는 컬럼들이 있을 수 있다.
이를 (이전적 함수 종속 관계)라고 한다.
제 3정규화는 PK에 의존하지 않고 일반컬럼에 의존하는 컬럼들을 분리한다.
1. 제 2정규화를 마쳤지만 여전히 중복된 값(노란색) 이 보인다.
2. 저 레코드는 author_id에 의존하는 컬럼들이다. 언뜻보면 title에 의존하는것처럼 보이지만 아닌것이다.
3. 그럼 PK(title)에 의존하지 않는 컬럼들을 분단시키자.
4. author라는 테이블을 만들고 중복되는 컬럼들 3개를 그대로 따온다. 그리고 topic테이블과 author_id로 외래키 관계를 맺어준다. 그러면 중복이 사라지는것을 볼 수 있다.
Q. 그런데 만일 author_id가 없고 author<name, author_profile만 있으면 어떻게 될까?
그래도 여전히 중복을 나타낸다.
이때 저 중복된 컬럼들을 따로 빼고, PK를 외래키로 가져오거나 아니면 구분할수있는 새로운 컬럼을 만들어서 위와같이 연결해주는 것도 나쁘지 않다.
결국, 정규화 과정이란
중복된 속성을 최소화 하고 종속관계에 있는 속성을 제거하는 과정이다.
이러한 정규화 과정을 다시 조인하면 데이터의 손실없이 이전상태로 복구가 가능해야 한다.
역정규화
-> 논리적 정규화를 통해 만든 표를, 개발적 측면에서 성능이나 편의성을 위해서 되돌아가는 작업을 일컫는다.
그렇다고 정규화를 한다고 해서 반드시 성능을 떨어뜨리는 것이 아니기 때문에 일반화 하지는 말자.
다음과 같은 정규화를 마친 논리적 테이블들이 있다고 하자.
[ 원본 테이블 ]
역정규화 - JOIN을 줄이기
1. 만일 topic_tag_relation의 topic_title필드를 가지고 tagName을 알아야된다고 해보자.
2. 그러면 topic_tag_relation과 tag테이블을 조인해서 조건에 부합하는 name컬럼 값을 가져오면 된다.
3. 하지만 만일 저러한 쿼리가 서버내에서 많이 일어날 경우, join은 많은 부하가 일어나길 마련이다.
4. 이때 그냥 테이블을 하나로 합쳐버리는 것이다.
5. 제 1정규화를 통해 나눴던 걸 성능과 편의를 위해서 역으로 되돌아가버린 것이다.
역정규화 - 계산 작업을 줄이기
이번에는 데이터를 처리하는 비용을 줄이기 위한 역정규화 이다.
1. 만일 count 값이 필요하다고 가정하자. group by를 통해 컬럼을 묶고 조회하면 된다.
2. 하지만 만일 이러한 쿼리가 빈번하게 이러난다면 역시 부하가 일어난다.
3. 따라서 그룹핑해서 내장함수를 쓰는게 아닌 아예 topic_count데이터를 컬럼 추가하는 것이다. topic_count 필드를 추가하고 데이터를 준다.
4. 하지만 유효한 데이터를 유지하기 위해서는 글이 추가될때마다 지속적으로 데이터를 업데이트해야 하는 관리를 해야 한다.
5. 트리거를 쓰던지 서버 사이드에서 처리하던지 하면 된다.
6. 관건은 group by 부하를 줄이는 것이기 때문이다.
역정규화 - 테이블 분리
하나의 표를 성능을 위해서 여러개로 쪼개는 경우이다.
만일 topic테이블에 description의 용량이 엄청많을때 만일 topic테이블을 자주 조회했을 경우 약간 부하가 올수도 있다.
그래서 표의 성능을 위해 용량이 큰 테이블을 따로 분리하는 것이다.
테이블을 나누면 여러대의 서버에서 각기 다르게 접근해서 처리할수 있으니 성능이 좋다.
행을 기준으로 분리하는것은 만일 author_id 회원이 몇만명일때, 하나의 테이블에 접근해서 처리하는것보다, 테이블을 분담해서 author_id가 1000이하일 경우 1500이상일 경우 각기 다른 테이블로 접근해서 부하를 줄이는 것이다.
mySQL에는 파티션 기법이 있는데, 바로 이걸 말하는 것이다.
역정규화 - 외래키 줄이기
join을 줄여서 지름길을 만드는 테크닉이다. 처음에 배웠던 역정규화 - JOIN을 줄이기 방법에서 외래키를 통해서 줄이는 방법이라 보면 된다.
어느 저자의 태그아이디와 태그명을 조회한다고 가정 했을때, 우리는 세가지 필드 어느 저자인지(autor_id), tag_id, tagName 이 필요하다 이들을 조회 하기 위해선 3개의 테이블을 join하고 불러오면 되지만, join을 많이 쓰면 성능이 안좋아진다. 그래서 topic_tag_relation테이블에 author_id컬럼을 추가하면, join을 한번만 하면 원하는 결과를 얻을 수 있다.
# 참고자료
https://myeonguni.tistory.com/210
https://www.opentutorials.org/course/3883/25301
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.