이번 게시글에서는 데이터 모델링 과정에 대해 정리합니다.
dba가 아니더라도 RDB를 사용하는 사람이라면 최소한 알고 있어야되는 약식 스키마설계(데이터모델링) 방법은 rdb를 사용하는 사람이라면 꼭 알아야 합니다.
1. 데이터모델링(스키마설계)란
데이터 모델링이란 복잡한 현실 세계에 존재하는 데이터를 단순화 시켜 표현해 컴퓨터 세계의 데이터베이스로 옮기는 변환 과정입니다.
DBA없이 일반 백엔드 개발자끼리 모여서 RDB를 사용하는 개발을 진행하게 되면
db설계 툴을 이용해서 1:n 같은 관계를 고민하고, 테이블설계를 하고 결과를 컨플루언스같은 문서에 올리고, orm의 entity나 sql의 결과를 매핑해올 vo를 구축할 생각을 먼저하며 DB설계를 시작합니다.(erwin 같은것들이 무겁고 불편해서 아에 테이블정보를 기록하고있지 않다면 가벼운 dbdiagram이라도 꼭 사용해야합니다)
나쁘지 않습니다만 이렇게 설계를 하면 필요한 필드를 빼먹을 수도 있고, 나중에 내 테이블에 중복이 많고 레코드가 너무 많아지고, 필요없는 데이터까지 가져오는거같고, insert나 delete를 하는데 뭔가 불필요한 추가로직이 필요하게 되는 상황이 오게 될 수도 있습니다.
데이터 모델링에 대해 알고나면 왜 이런 중복이 발생했는지 뭐가 잘못된건지를 확인할 수 있고
앞으로 조금 더 가용성좋은, 확장하기 좋은 구조의 스키마를 설계할 수 있습니다.
2. 데이터 모델링 과정
- 개념적 데이터모델링
- 논리적 데이터모델링
- 물리적 데이터모델링
크게 세가지 단계로 나뉩니다. 각각의 단계에서 하는일이 무엇인지 정리하고
스키마가 오염된 DB가 무엇인지, 무엇때문에 오염 되는지 정리합니다.
3. 개념적 데이터 모델링
현실세계의 각각의 개념은 어떻게 상호작용하는지를 파악하는 단계이며
entity, attribute, relation을 정의하는 단계입니다.
결과물로 entity relation diagram이라고 불리는 erd가 나옵니다.(erd er다이어그램 으로 불립니다)
erd에는 엔티티(개체), 어트리뷰트(속성), 릴레이션(관계) 라는 용어가 등장하니 하나씩 정리해보겠습니다.
(1). entity(개체)
entity는 현실세계의 정보들을 그루핑 한 것 입니다.
추후 rdb 테이블의 이름이 됩니다.
JPA를 사용해보신 분은 바로 느낌이 올것같습니다.
@Entity라는 어노테이션을 붙여줬던 바로 그 컴포넌트입니다.
(2). attribute(속성)
attribute는 현실세계의 정보이며 attribute가 모여서 entity가 됩니다.
ORM의 entity나 VO의 멤버필드라고 생각하시면 됩니다.
나중에 테이블의 컬럼(필드)에 매핑됩니다.
(3). relation(관계)
relation은 이제 1:n n:m 등을 결정짓는 요소입니다.
JPA라면 추후 @OneToMany 등의 어노테이션을 쓸수있도록 관계를 정의 합니다.
ORM을 위한 entity 클래스와 비교해보겠습니다.
class User {
int id
string name
Card[] cards
}
클래스명인 User는 entity(개체), id와 name은 attribute(속성), Card는 relation(관계) 라고 보시면 됩니다.
화면기획서를 보고 모든 테이블, 체크박스, 라디오박스, input박스 selectbox 등을
모두 attribute에 넣고(사용자의 모든 input은 어디엔가 저장되야합니다.)
attribute를 묶어 entity를 만들어 다른 entity들간의 relation을 만든다라고 생각하면 됩니다.
처음에 이러한 정보를 파악해야하는데 화면기획서가 있어야 파악하기 쉽습니다.
화면기획서가 없다면 피그마, 카카오오븐, drawio 등을 사용하여 간단하게 화면기획서를 그리거나,
화면기획서가 나오지않고, 필요하지도 않다면 손으로라도 그려서 뭐가 필요한지 정의하고 시작해줍니다.
entity, attribute, relation을 정의했다면 ERD를 그려야하지만,
ERD를 그릴 시간적 여유가 없다면 굳이 ERD를 배워서 그리지는 말고 다음단계로 넘어가 다음단계에 시간을 투자합니다
4. 논리적 데이터 모델링
DB설계의 꽃 논리 데이터 모델링 단계입니다.
논리적 데이터 모델링을 잘 해놓지 않으면 RDB의 이상현상을 경험할수도 있으며 뭔가 자꾸 중복되는거같고 불필요한 데이터를 뽑아내는거 같은 느낌이 듭니다.
이상현상: (뭔가를 insert해야하는데 자꾸 불필요한 데이터까지 있어야 insert를 할수있게 되는것같고, 뭔가를 삭제하고싶은데 같은 레코드에 있는 필요한 정보까지 삭제되야 돼서 뭔가 불필요한 추가로직을 심게되는.. 등)
그러한 느낌이 드는 이유는 논리적 데이터 모델링 단계에 정규화 단계가 포함되어있기 때문입니다.
정규화를 알고나면, 조금 더 가용성좋고 확장하기 좋은 구조의 스키마를 설계할 수 있습니다.
정규화란 테이블을 쪼개 중복된 데이터를 없애는 것입니다.
정규화를 잘 해놓는다면 무결성을 유지하고 DB용량을 줄일 수 있습니다.(대신 join의 비용은 늡니다 join의 비용을 줄이기위해 강제로 정규화된 테이블을 합치는것을 반정규화라고 합니다.)
정규화에는 많은 종류가 있지만 3정규화이상 되어있다면 정규화된 테이블이라고 부르기 시작합니다.
(1). 1정규화
1정규화는 모든 속성이 도메인 원자값으로 구성되어 있도록 바꾸는 과정을 말합니다.
1정규형을 만족한 테이블은 1정규화가 만족됐다고 합니다.
여기 정규화되지 않은 User 테이블이 있습니다.
John의 핸드폰이 두개네요
NAME | AGE | PHONE_NUMBER |
Tom | 20 | 010-1111-1111 |
John | 21 | 010-1111-2222, 010-2222-3333 |
이렇게 정규화를 해보겠습니다.
NAME | AGE | PHONE_NUMBER1 | PHONE_NUMBER2 |
Tom | 20 | 010-1111-1111 | null |
John | 21 | 010-1111-2222 | 010-2222-3333 |
잘못된 방법입니다.
이번에는 이렇게 정규화를 해보겠습니다.
NAME | AGE | PHONE_NUMBER |
Tom | 20 | 010-1111-1111 |
John | 21 | 010-1111-2222 |
John | 21 | 010-2222-3333 |
이것도 잘못된 방법입니다.
정규화란 테이블을 쪼개서 중복을 최소화 하는 과정입니다.
테이블을 쪼개봅시다.
NAME | AGE |
Tom | 20 |
John | 21 |
PHONE 테이블을 만듭니다.
user와 phone은 1:n 관계이므로 phone에 외래키를 걸어줍니다.
PHONE_NUMBER | USER_NAME |
010-1111-1111 | Tom |
010-1111-2222 | John |
010-2222-3333 | John |
user테이블과 phone테이블로 테이블이 쪼개지면서
모든 속성이 도메인 원자값이 되며 1정규화가 완성됐습니다.
(2). 2정규화
1정규형을 만족하면서 기본키가 아닌 속성이 기본키에 완전 함수 종속이면 제 2정규형 이라고 합니다.
(부분 함수 종속을 제거한다고도 합니다)
기본키가 아닌것들은 기본키가 결정되면 모두 결정되도록 만들어줍니다.
테이블을 보다가 기본키와 후보키가 모여 중복키가 돼서 나머지를 결정지을 수 있다면2정규화를 해주면 됩니다.
뭔가 섞인듯한 테이블이 보입니다.
학번 | 이름 | 과목코드 | 성적 | 학과 | 성별 |
111 | John | A01 | A | 컴퓨터공학과 | 남 |
112 | Tom | A02 | B | 전자통신공학과 | 남 |
학번이 결정되면 학과와 성별이 결정되는건 상관없는데
학번과 과목코드가 결정되면 이번학기 그 과목의 성적이 결정되버립니다.
기본키와 후보키가 모여 중복키가 돼서 성적을 결정지어버리는걸 보니 2정규화가 필요합니다.
학번 과목코드 성적을 따로 빼서 테이블을 만들어줍니다.
학번 | 과목코드 | 성적 |
111 | A01 | A |
112 | A02 | B |
학번 | 이름 | 학과 | 성별 |
111 | John | 컴퓨터공학과 | 남 |
112 | Tom | 전자통신공학과 | 남 |
뭔가 어지러운 테이블이었는데 정규화를 하고보니 성적테이블과 학생테이블로 나누어졌습니다.
부분 함수 종속을 제거해서 2정규화가 완성되었습니다.
(3). 3정규화
1정규화를 만족하고, 2정규화를 만족한 상황에서
이행 함수종속을 제거하면 3정규화를 만족하게 됩니다.
이행 함수종속이란 기본키가 결정되면 나머지 것들이 결정되야 하지만
기본키가 결정돼서 그중의 하나의 값이 결정되는순간 나머지것들이 그중 하나의 값때문에 결정되는 상황을 말합니다.
무슨말인지 이해가 어려우니 직접 테이블로 보겠습니다.
3정규화가 필요한 테이블은 비교적 중복이 눈에 잘 띕니다.
책 제목 | 가격 | 저자 | 저자의 자기 소개 | 저자 성별 |
clean code | 1000 | 로버트C마틴 | hello | 남자 |
clean architecture | 1500 | 로버트C마틴 | hello | 남자 |
code | 2000 | 찰스펫졸드 | hi | 남자 |
책이 결정되면 모든게 결정되긴 하지만,
책이 결정되는순간 저자가 결정되고 저자가 결정되는 그 순간 저자의 자기소개, 저자 성별이 결정됩니다.
이걸 이행 함수 종속이라고하고 제거해서 중복을 제거해야합니다.
한명의 저자는 여러권의 책을 쓸수 있다고 가정하겠습니다.
저자 책 = 1 : n 관계입니다.
꼭 n쪽인 책에다가 외래키를 걸어주도록 합니다.(1쪽에 외래키를 거는순간 스키마가 오염됩니다)
책 제목 | 가격 | 저자 |
clean code | 1000 | 로버트c마틴 |
clean architecture | 1500 | 로버트c마틴 |
code | 2000 | 찰스펫졸드 |
저자 | 저자의 자기소개 | 저자 성별 |
로버트c마틴 | hello | 남자 |
찰스펫졸드 | hi | 남자 |
책 테이블과 저자 테이블로 테이블이 쪼개지며
3정규화가 완성되었습니다.
정규화 단계가 추가로 있긴하지만 3정규화까지만 되있으면 정규화되었다고 하니
3정규화까지는 고려하며 설계를 하도록 합니다.
4. 물리적 데이터 모델링
물리적 데이터 모델링은 이제 ddl을 작성하여 물리적인 테이블을 만드는 과정입니다.
DBA들은 테이블을 만들기 전에 복잡한 테이블 구조만보고 어디에서 병목이 생기는지 분석하고
슬로우 쿼리를 찾아내서 반정규화를 해준다고합니다.(join의 비용이 줄도록)
테이블구조로 슬로우쿼리를 분석하라는건 어려우니
조회가 중요한 테이블에 인덱스라도 설계해주고(인덱스를 걸면 조회성능이 향상되고 insert 관련 성능이 줄어듭니다.)
확장될 여지가 없는 테이블정도만 반정규화를 고려해봅니다.
최종적으로 ddl을 작성하거나 애플리케이션의 도움을 받아 table이 생성된 순간, DB설계는 완성됩니다.
5. DB 스키마가 오염되는 이유
DB 스키마는 개념적 모델링을 제대로 하지 못하여(확장을 고려하지 않아서) 엔티티를 불분명하게 선정하고, 논리 모델링 단계에서 정규화도 제대로 하지 않은 테이블에 필드 추가를 할때 쉽게 오염됩니다.
엔티티선정도 잘못되었고, 정규화가 되어 있지않으면 이게 뭘 위한 테이블인지 굉장히 모호해지고 필요에 따라 입맛대로 컬럼을 추가하면서 DB 스키마가 오염되게 됩니다.
DB 스키마는 한번 오염돼서 운영되면 테이블에 데이터가 들어있기에 변경하기 힘듭니다.
5. 마치며
데이터 모델링을 하는 방법을 정리해봤습니다.
DB툴만 사용해서 약식으로 스키마 설계를 진행하는 경우가 많으므로
약식으로 진행하더라도 꼭 고려했으면 하는 정보들을 정리해 봤습니다.
정석은 개념적 모델링의 결과인 erd와 논리, 물리 데이터모델링의 결과를 erwin 같은 데이터모델링 툴에 모두 올려놔야 합니다.
약식으로 진행하더라도 아래처럼 DB툴을 사용하여 꼭 정리하도록 합니다.
'개발상식' 카테고리의 다른 글
[개발상식] 유저레벨스레드(Green Thread) vs 커널레벨스레드(Native Thread) (0) | 2021.12.01 |
---|---|
[개발상식] 메모리란(DISK IO가 느린 이유, 램이 사용되는 곳) (0) | 2021.11.25 |
[개발상식] tdd란 (tdd 예제, tdd하는법) (1) | 2021.11.16 |
[개발상식] 객체지향 설계 5대원칙(solid)이란 (0) | 2021.09.09 |
[개발상식] 프로세스간 통신(IPC) (1) | 2021.08.25 |
댓글