DB schema 설계를 잘못하면 어떤 문제가 생길까?
바로, 이상 현상(Anomaly)이 생기는 것이다.
이상 현상은 삽입 이상(Insertion Anomaly), 삭제 이상(Deletion Anomaly), 갱신 이상(Modification or Update Anomaly), 으로 구성된다.
하나하나 살펴보자.
예를 들어, IT 회사의 DB를 구축하는데 다음과 같은 테이블을 만들었다고 가정해보자.
EMPLOYEE_DEPARTMENT
empl_id empl_name birth_date position salary dept_id dept_name dept_leader_id
임직원 정보와 부서 정보를 하나의 테이블에 저장할 수 있도록 설계를 한 예시이다. (empl_id
가 primary key이다.)
이때, 데이터를 write (insert, update, delete) 하게 되면 어떤 문제가 생길까?
먼저 데이터를 추가할 때, insertion anomalies가 발생하게 된다.
예를 들어, 임직원 정보를 하나 추가한다고 가정해보자.
empl_id | empl_name | birth_date | position | salary | dept_id | dept_name | dept_leader_id |
---|---|---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 | DEV | 1 |
이렇게 SUNGGON이라는 임직원을 하나 추가할 때는 문제가 없다.
데이터를 하나 더 추가해보자.
empl_id | empl_name | birth_date | position | salary | dept_id | dept_name | dept_leader_id |
---|---|---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 | DEV | 1 |
2 | MINWOO | ... | ... | ... | 1001 | DEV | 1 |
MINWOO라는 임직원을 한명 더 추가했다.
여기서, 부서(dept) 파트를 살펴보자.
이 부분은 중복 데이터가 된다.
부서의 아이디(1001
), 부서 이름(DEV
), 부서 리더의 아이디(1
) 가 같은, DEV팀의 데이터가 중복으로 발생한다.
이러한 중복 데이터는 다음과 같은 문제점이 있다.
dept_name
에 DEB
라고 작성한다면 같은 데이터임에도 불구하고 데이터 불일치가 발생할 수도 있는 것이다.그래서 가능하다면 중복 데이터는 최대한 줄이는 것이 좋다.
이어서, 만약 아직 부서 배치를 받지 못한 직원을 추가하게 된다면 어떻게 될까?
empl_id | empl_name | birth_date | position | salary | dept_id | dept_name | dept_leader_id |
---|---|---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 | DEV | 1 |
2 | MINWOO | ... | ... | ... | 1001 | DEV | 1 |
3 | SEHOON | ... | ... | ... | ? | ? | ? |
아직 부서 배치를 못받은 SEHOON이라는 직원이 들어왔다.
?
값에는 어떤 값들이 들어가야 할까?
부서와 관련된 attribute가 있음에도 불구하고 저기에는 일단 null
데이터를 넣어야 한다.
그러나, null값을 많이 쓰는 것은 좋은 것이 아니다. 즉, 가능한 null 값은 적게 쓰는 것이 좋다.
이어서, 또 다른 데이터를 추가해보자.
그러나 이번에 넣을 데이터는 임직원이 한 명도 없는 부서 정보만 입력하는 것이다.
empl_id | empl_name | birth_date | position | salary | dept_id | dept_name | dept_leader_id |
---|---|---|---|---|---|---|---|
1 | SUNGGON | .... | ... | ... | 1001 | DEV | 1 |
2 | MINWOO | ... | ... | ... | 1001 | DEV | 1 |
3 | SEHOON | ... | ... | ... | null | null | null |
4 | ? | ? | ? | ? | 1002 | QA | null |
QA팀의 아이디, 이름이 입력 되었지만, 소속된 임직원이 아무도 없기에 리더의 아이디가 없다.
또한, 소속된 임직원이 없기에 ?
에는 null값이 입력된다.
이때, empl_id
는 primary key이기에 null값을 가질 수 없기에 임시로 4라는 값을 넣어주게 된다.
이 상황에서, QA팀에 첫 직원이 들어왔다고 해보자.
empl_id | empl_name | birth_date | position | salary | dept_id | dept_name | dept_leader_id |
---|---|---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 | DEV | 1 |
2 | MINWOO | ... | ... | ... | 1001 | DEV | 1 |
3 | SEHOON | ... | ... | ... | null | null | null |
4 | ? | ? | ? | ? | 1002 | QA | null |
5 | HYUNJIN | ... | ... | 5000 | 1002 | QA | 5 |
QA팀에 HYUNJIN이라는 첫 직원이 들어왔다. (그렇게 현진은 리더가 된다.)
이제 부서 정보를 저장하기 위해 임시로 넣어뒀던 4번 row의 정보는 삭제를 해야하는 번거로움이 발생한다.
왜 이러한 문제가 발생했을까?
두 개의 관심사 (임직원 정보와 부서 정보)를 한 테이블에서 관리하려고 했기 때문이다. 즉, 별개의 관심사가 한 테이블에 있는 것이 원인이다.
테이블을 설계할 때는 관련있는 하나의 관심사만 묶어서 테이블로 설계하는 것이 바람직한 방법이다.
각각에 대한 것을 따로 테이블로 만들어주면 다음과 같이 설계할 수 있다.
<EMPLOYEE>
empl_id | empl_name | birth_date | position | salary | dept_id |
---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 |
2 | MINWOO | ... | ... | ... | 1001 |
3 | SEHOON | ... | ... | ... | null |
5 | HYUNJIN | ... | ... | 5000 | 1002 |
<DEPARTMENT>
dept_id | dept_name | dept_leader_id |
---|---|---|
1001 | DEV | 1 |
1002 | QA | 5 |
임직원 테이블은 empl_id
가 primary key가 되고, 부서 테이블은 dept_id
가 primary key가 된다.
임직원 테이블에 있는 dept_id
는 부서 테이블의 dept_id
를 레퍼런스하는 외래 키(foreign key)가 된다.
여기서 새로운 임직원을 추가해보자.
empl_id | empl_name | birth_date | position | salary | dept_id |
---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 |
2 | MINWOO | ... | ... | ... | 1001 |
3 | SEHOON | ... | ... | ... | null |
5 | HYUNJIN | ... | ... | 5000 | 1002 |
6 | CHANIK | ... | ... | ... | ? |
CHANIK이라는 새로운 임직원을 추가 했을 때, 임직원 테이블에 추가를 하면 된다.
CHANIK이라는 직원이 아직 부서를 배정받지 못했을 경우, dept_id
만 NULL
값을 주면 되는 것이고, 만약 DEV팀이라면 1001
이라는 값을 넣어주면 되는 것이다.
추가적으로, 새로운 부서 정보를 입력하게 된다면 어떻게 될까?
다음 표와 같이 부서 테이블에만 새로운 데이터를 추가하면 되는 것이다.
dept_id | dept_name | dept_leader_id |
---|---|---|
1001 | DEV | 1 |
1002 | QA | 5 |
1003 | DESIGN | NULL |
이러한 방식으로 테이블을 잘 설계한다면 중복된 데이터를 줄일 수 있고 NULL 값도 적게 쓰게 되며 훨씬 더 깔끔하게 데이터를 다룰 수 있다.
다시 이전의 개떡같은 스키마를 보자.
empl_id | empl_name | birth_date | position | salary | dept_id | dept_name | dept_leader_id |
---|---|---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 | DEV | 1 |
2 | MINWOO | ... | ... | ... | 1001 | DEV | 1 |
3 | SEHOON | ... | ... | ... | null | null | null |
5 | HYUNJIN | ... | ... | 5000 | 1002 | QA | 5 |
이 테이블에서 HYUNJIN의 정보(tuple)를 삭제하면 어떻게 될까?
현재, HYUNJIN은 QA 팀에 사수도 부사수도 없는 최후의 1인이다.
empl_id | empl_name | birth_date | position | salary | dept_id | dept_name | dept_leader_id |
---|---|---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 | DEV | 1 |
2 | MINWOO | ... | ... | ... | 1001 | DEV | 1 |
3 | SEHOON | ... | ... | ... | null | null | null |
HYUNJIN의 정보를 삭제하게 된다면 QA 팀에 대한 데이터 자체도 사라지게 된다.
이 문제를 해결하기 위해선 QA 팀에 대한 정보는 놔두고, HYUNJIN에 대한 데이터만 NULL값을 주는 것이다.
empl_id | empl_name | birth_date | position | salary | dept_id | dept_name | dept_leader_id |
---|---|---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 | DEV | 1 |
2 | MINWOO | ... | ... | ... | 1001 | DEV | 1 |
3 | SEHOON | ... | ... | ... | null | null | null |
5 | null | null | null | null | 1002 | QA | 5 |
하지만, 이 역시 null 값이 많이 쓰일 뿐더러 한눈에 봐도 괴상한 형태이다.
만약, 임직원 테이블과 부서 테이블을 따로 설계후 delete를 한다면 다음과 같다.
<EMPLOYEE>
empl_id | empl_name | birth_date | position | salary | dept_id |
---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 |
2 | MINWOO | ... | ... | ... | 1001 |
3 | SEHOON | ... | ... | ... | null |
<DEPARTMENT>
dept_id | dept_name | dept_leader_id |
---|---|---|
1001 | DEV | 1 |
1002 | QA | null |
임직원 테이블에서만 HYUNJIN의 데이터를 삭제하면 되고, 부서 테이블은 dept_leader_id
만 null값으로 바꾸면 되는 것이다.
empl_id | empl_name | birth_date | position | salary | dept_id | dept_name | dept_leader_id |
---|---|---|---|---|---|---|---|
1 | SUNGGON | ... | ... | ... | 1001 | DEV | 1 |
2 | MINWOO | ... | ... | ... | 1001 | DEV | 1 |
3 | SEHOON | ... | ... | ... | ? | ? | ? |
잘못된 DB 스키마의 설계는 Spurious Tuples(가짜 튜플)이라는 문제점을 발생할 수도 있다.
예제를 통해서 Spurious Tuple에 대해 알아보자.
REF.
쉬운코드 - DB 테이블 설계 잘못하면 어떤 문제가 생길 수 있을까요?
데이터베이스 이상 현상(Anomaly) 개념과 예시
관계형 데이터 베이스의 함수적 종속성