- inflearn : https://www.inflearn.com/course/비전공자-db-설계-입문/dashboard
- 수업 자료: https://jscode.notion.site/d551b000ffac42879d8630cd7edd618f
Preview
회사에서 무작정 DB 설계를 시작했고 학부시절 그리고 자격증 취득 과정에서 배웠던 개념은 머릿속에서 떠난지 오래다. 이미 어느정도 정규화 하는 절차에 대해서 알고 있었지만 개념적인 부분을 공부해서 조금 다듬을 필요가 있었다. 강의시간이 너무 길지도 않고 단순 이론에 치중하지도 않고 실무 위주의 강의를 찾던 중 해당 강의를 찾게 되어 학습하게 되었다.
Introduce
공부는 어렵게 해야 한다.
- 코딩 공부를 할 때 단순 듣기와 단순 코드 따라치기가 가장 비효율적인 공부 방법이다.
- 더 최악인 것은 따라치기를 통해 스스로가 이해하고 있는 착각을 불러 일으킨다.
- 따라서 공부는 어렵게 해야 한다.
효율적인 공부를 하기 위한 방법으로는 아래 방법들이 있다.
- 요약하기
- 나만의 말로 바꿔서 글을 쓴다.
- 남에게 설명을 한다.
- 그림을 도식화 한다.
위 방법들을 실천하기 위한 가장 좋은 방법은 학습한 내용을 정리하여 “블로그에 업로드” 하는 것이다.
파레토 법칙(Pareto principle)
- 파레토의 법칙에 따라 공부를 하는 것이 좋다.
- 파레토 법칙이란 현업에서 자주 사용되는 개념인 20%만 익혀도 80%의 효율을 낸다.
- 현업에서 사용하는 기술을 우선적으로 공부하고 현업에 돌입하여 필요한 내용만 추가적으로 공부를 하는 것이 효율적이다.
First Word 법칙
- 직관적으로 이해가 되지 않는 용어를 잘 정리한다.
- 처음 들어본 용어이거나 낯선 용어는 반드시 기록해둔다. 나중에 사전처럼 꺼내서 읽어본다.
필수 개념
데이터베이스 모델링(Database Modeling) 이란?
- 데이터를 어떻게 분류해서 저장할 지를 설계하는 행위
- 데이터베이스 설계라도고함
- 효율적으로 데이터를 저장하고 가져오기 위한 방법
관계형 데이터베이스 (RDBMS)의 기본 구성
- 테이블(Table), 컬럼(Column), 로우(Row)의 구성 요소가 있다.
PK(기본키), FK(외래키)
- PK(Primary Key, 기본키)
- 특정 데이터를 식별하기 위한 값
- 중복되어서는 안 되며, 비어있어서도 안 된다.
- PK는 값이 변경되는 것을 권장하지 않는다. 따라서 현업에서는 주로 Auto Increment(숫자가 1씩 증가하는 방식)또는 UUID(랜덤값)로 설정을 많이 한다.
- FK(Foreign Key, 외래키)
- 다른 테이블의 데이터와 관계를 연결하기 위한 키
- FK는 PK를 저장하는 것이 일반적이다.
- FK는 적절하지 않은 FK를 넣었을 때 에러를 발생시킨다. (참조 무결성)
데이터베이스 네이밍 규칙
- 테이블명, 컬럼명은 소문자로 작성한다.
- snake_case를 사용한다.
- 축약어를 사용하지 않는다.
- SQL 쿼리를 작성할 때는 예약어만 대문자로 표현하라 (SELECT, FROM, AND, OR 등등)
- 테이블명을 지을 때는 복수형을 사용한다. (user→users, post→posts)(선택사항)
DB 설계 핵심 원칙 및 전체 과정
아래 사항은 현재 시점에서 꼭 공부할 필요는 없다.
- 기본키, 후보키, 대체키, 슈퍼키
- 개체-관계 모델
- 모델링 과정 (개념적 모델링, 논리적 모델링, 물리적 모델링)
- 이상현상(삭제 이상, 삽입 이상, 수정 이상)
- 함수 종속성
- 제1정규형 ~ 5정규형, BCNF 정규형 / 부분적 함수 종속, 이행적 함수 종속
DB 설계 시 꼭 기억해야 할 핵심 원칙 1가지
- 데이터베이스를 설계할 때의 핵심은 “중복 없애기” 이다.
- 저장된 데이터들 중에서 모순되는 상황이 생긴 현상을 이상현상(Anomaly)라고 한다.
- 중복 없애기를 위한 DB 설계 방법이 정규화(Normalization) 이다.
정규화(Normalization)
- 데이터들 사이에서 발생한 모순의 근본적인 원인은 데이터 중복이다.
- 이러한 문제를 해결하려면 데이터 중복을 없애면 된다.
- DB를 설계하면서 중복을 없애는 과정이 정규화이다.
- 제1정규형, 제2정규형, 제3정규형 등 모든 정규형은 중복을 없애게 해주는 방법이다.
- 현업에서는 1,2,3 정규형까지만 주로 적용한다.
DB 설계 전체 과정
- 저장해야 하는 데이터 파악하기
- 데이터베이스를 설계하기 전에 어떤 데이터를 저장해야 하는 지 파악해야 한다. 그러려면 대략적인 UI 디자인이 나와 있어야 한다. 또는 요구사항 정의서가 나와 있어야 한다.
- 그룹핑해서 분류하기ex) 아이디, 패스워드, 이름, 이메일 → 사용자
- ex) 게시글 제목, 게시글 내용, 작성자 → 게시글
- 저장해야 하는 데이터를 묶어서 그룹핑할 수 있는 상위 개념을 찾는다.
- 6가지 규칙 적용시키면서 테이블 분리해나가기
저장할 데이터 파악하기
- 요구사항을 보면서 데이터에 어떤 데이터를 저장해두어야 할 지 파악하는게 가장 먼저다.
- 어떤 데이터를 저장해두어야 하는 지 파악해야, 어떤 방식으로 데이터를 분류해서 저장할 지 결정할 수 있다.
그룹핑해서 분류하기
- 저장해야 하는 데이터를 묶어서 그룹핑 할 수 있는 상위 개념을 찾아야 한다.
- 이렇게 그룹핑 된 하나의 그룹을 보고 데이터베이스에서는 엔티티(Entity)라고 한다.
- 엔티티(Entity)가 데이터베이스의 테이블(Table)이라고 생각해도 된다.
테이블로 나타내기
- users (사용자)
id | password | name | |
1 | test@mail.com | qwer1234! | jay |
2 | test1@mail.com | qwer1234! | kim |
DB 설계 규칙 6가지
[규칙 1] 한 칸에는 한 가지 정보만 들어가도록 만들어라
DB 테이블을 설계 할 때 ‘한 칸에는 한 가지 정보만 들어가야 한다.’라는 규칙을 지켜야 한다. 규칙을 지키지 않은 사례는 아래와 같다.
- users(사용자)
id(PK) | name | |
1 | parkjh | parkjh@gmail.com, jhpark@gmail.com |
2 | parkmj | parkmj@gmail.com, mjpark@gmail.com |
데이터를 콤마(,) 로 구분하는 것이 좋지 않은 선택인 이유
- 데이터를 추가,수정,조회 하는 과정에서 매번 콤마로 분류하는 복잡한 로직이 추가되어야 한다.
- 중복을 허용하게 될 수도 있다.
한 칸에 2개 이상의 정보가 들어가 있다면 ? → 테이블을 분리한다.
- users(사용자)
id(PK) | name |
1 | parkjh |
2 | parkmj |
- emails(이메일)
id(PK) | user_id(FK) | |
1 | parkjh@gmail.com | 1 |
2 | jhpark@gmail.com | 1 |
3 | parkmj@gmail.com | 2 |
4 | mjpark@gmail.com | 2 |
이 과정을 보고 데이터베이스 이론에서는 제1정규형 이라고 부른다.
데이터베이스 설계는 처음 딱 고정한 대로 끝까지 가는 것이 아니라 상황에 따라 기획에 따라 변경할 수 있어야 한다.
요약
- 한 칸에는 한 가지 정보만 들어가야 한다.
- 한 칸에 두 가지 이상의 정보가 들어가있을 땐 테이블을 분리해서 FK를 활용하면 된다.
- 특정 테이블에 FK를 도입했을 때 규칙 1이 안 지켜진다면, 다른 테이블로 FK를 옮겨보자.
- ‘한 가지 정보’의 기준은 절대적이지 않다. 따라서 서비스에 맞게 판단해야 한다.
[규칙 2] 어떤 테이블에 FK를 넣어도 ‘규칙 1’을 지키지 못할 때는 중간 테이블을 하나 더 만들어라
아래 테이블의 규칙 1과 같이 적용하기에는 중복이 명확하게 제거되지 않는다.
- students (학생)
id(PK) | name | courses |
1 | 김철수 | 수학, 과학 |
2 | 박민지 | 국어, 수학 |
3 | 조혜진 | 국어, 과학 |
- courses (수강과목)
id(PK) | name | student_id(FK) |
1 | 수학 | 1,2 |
2 | 과학 | 1,3 |
3 | 국어 | 2,3 |
아래와 같이 테이블을 하나 더 추가해서 개선할 수 있다.
- students (학생)
id(PK) | name |
1 | 김철수 |
2 | 박민지 |
3 | 조혜진 |
- courses (수강과목)
id(PK) | name |
1 | 수학 |
2 | 과학 |
3 | 국어 |
- students_courses → 테이블명을 동사를 생각 하면 좀 더 가독성 생긴다 (course_registrations)
id(PK) | student_id(FK) | course_id(FK) |
1 | 1 | 1 |
2 | 1 | 2 |
3 | 2 | 1 |
4 | 2 | 3 |
5 | 3 | 2 |
6 | 3 | 3 |
[규칙 3] 헷갈릴 땐 관계(1:1, 1:N, N:M) 를 파악해봐라
규칙 1과 규칙 2가 헷갈릴 땐 엔티티 간의 관계를 파악한다.
엔티티 관계 파악 방법
엔티티 간에 어울리는 동사 찾기
- A(주어)가 B를 ___. (A가 주어)
- B(주어)가 A에 의해 ___. (B가 주어)
** 서비스의 관점에서 동사를 떠올려야한다.
1번 과정에서 찾은 동사를 활용해 적절한 단어 (하나의 or 여러개의) 찾기
- 하나의 A는 (하나의 or 여러 개의) B를 ___. (A의 관점)
- 하나의 B는 (하나의 or 여러 개의) A에 의해 ___ (B의 관점)
** 문장 처음에 시작하는 ‘하나의’ 라는 말을 반드시 붙어야 헷갈리지 않는다.
** 서비스를 어떻게 기획하냐에 따라 달라질 수 있다. 반드시 자신의 서비스에 대입해서 생각해야 한다.
관계 판단하기
- A, B의 관점 전부 다 ‘하나’만 가진다면 → A:B=1:1
- A의 관점에서는 ‘여러개’의 B를 가지고, B의 관점에서는 ‘하나’의 A를 가진다면 → A:B=1:N
- A의 관점에서는 ‘하나’의 B를 가지고, B의 관점에서는 ‘여러개’의 A를 가진다면 → A:B=N:1
- A, B 관점 전부 다 ‘여러개’를 가진다면 → A:B=N:M
아래 테이블을 예시로 관계를 파악해본다.
- users(사용자)
id(PK) | name |
1 | parkjh |
2 | kimsy |
- emails(이메일)
id(PK) | user_id(FK) | |
1 | parkjh@gmail.com | 1 |
2 | jhpark@gmail.com | 1 |
3 | kimsy@gmail.com | 2 |
4 | sykim@gmail.com | 2 |
- 엔티티 간에 어울리는 동사 찾기
- 사용자(A)가 이메일(B)을 소유한다.
- 이메일(B)은 사용자(A)에 의해 소유되어 진다.
- 1번 과정에서 찾은 동사를 활용해 적절한 단어(하나의 or 여러개의) 찾기
- 하나의 사용자(A)는 ‘여러 개’의 이메일(B)을 소유한다.
- 하나의 이메일(B)은 ‘하나’의 사용자(A)에 의해 소유되어진다.
- 관계 판단하기
- 사용자 : 이메일 = 1 : N
학생, 수강 과목 예제
- 학생이 수강 과목을 듣는다.
- 수강 과목이 학생에 의해 들어진다.
- 한 명의 학생이 여러 개의 수강 과목을 듣는다.(들을 수 있다).
- 하나의 수강 과목이 여러 명의 학생에 의해 들어진다.
- 학생 : 수강과목 = N : M
사용자, 프로필 예제
- 사용자는 프로필을 등록한다.
- 프로필은 사용자에 의해 등록되어진다.
- 하나의 사용자는 하나의 프로필을 등록한다.
- 하나의 프로필은 하나의 사용자에 의해 등록되어진다.
- 사용자 : 프로필 = 1 : 1
1:1 관계의 특징
- 아무 테이블에 FK를 넣어도 된다.
- 합쳐도 되는 지 고려해봐야 한다. (어지간하면 1:1 관계로 분리하지 않는 것을 추천한다.)
1:N 관계의 특징
- N 쪽의 테이블에 FK가 들어가야 한다.
N:M 관계의 특징
- 중간 테이블이 있어야 한다.
- 중간 테이블에 두 테이블의 FK가 들어가야 한다.
- N:M 관계에서 중간 테이블을 추가해 1:N 관계로 바꿔 표현하게 된다.
[규칙 4] 데이터 중복이 발생하는 컬럼이 있는 지 확인해라
- 데이터 중복이 발생하는지 시뮬레이션을 돌려봐라 → 테이블에 임의의 데이터를 하나씩 넣어보고 분석해본다.
- 아래 테이블은 작성자에서 중복이 발생함을 확인한다. 사용자 테이블을 하나 만들어 중복을 제거한다.
id(PK) | subject | contents | register |
1 | test1 | hello1 | parkjh |
2 | test2 | hello1 | parkjh |
3 | test2 | hello2 | parkmj |
[규칙 5] 가짜 중복과 진짜 중복을 구별해라
가짜 중복과 진짜 중복을 판단하기 위해서는 “실제 서비스에서 A 데이터의 값을 수정하면, B 데이터의 값도 수정해야 하는지 판단”하면 된다.
아래 테이블은 제목, 내용, 작성자 모두 중복이 발생하였다. 하지만 진짜 중복은 작성자 컬럼에서만 발생하였다. 판단 기준에 따르면 작성자가 변경되면 모든 데이터가 변경되어야 한다. 하지만 제목과 내용은 작성자가 변경되어도 다른 데이터를 변경할 필요는 없다.
id(PK) | subject | contents | register |
1 | test | hello | parkjh |
2 | test | hello | parkjh |
3 | test | hello | parkjh |
[규칙 6] 숨어있는 중복을 찾아라
아래 테이블은 중복이 없는 것처럼 보이지만 만약 사용자가 게시글의 좋아요를 취소하기 위해 likes 테이블의 해당 로우를 삭제한다면 좋아요 수도 변경되어야 한다. 하지만 만약 좋아요 수가 변경되지 않는다면 여기서 중복이 발생했을 때와 동일한 단점이 존재한다. 이처럼 숨어있는 중복은 주로 집계(합계, 평균, 최대값 등)의 값에서 많이 나타난다.
- posts (게시글)
id(PK) | subject | contents | likes | user_id(FK) |
1 | 제목1 | 내용1 | 2 | 1 |
- users (사용자)
id(PK) | name |
1 | 박지후 |
2 | 조혜진 |
- likes (좋아요)
id(PK) | user_id | post_id |
1 | 1 | 1 |
2 | 2 | 1 |
숨어있는 중복을 제거하기 위해서는 ‘좋아요 수’ 컬럼을 제거하고 ‘likes’ 테이블을 활용해서 ‘좋아요 수’를 카운팅 하는 것이 좋다. 데이터 중복을 허용하면서 나름의 편리함을 가져가는 데이터 역정규화라는 것이 있다. 우선은 고려하지 않는다.
ERD(Entity Relationship Diagram)란 ?
ERD(Entity Relationship Diagram) = 엔티티(테이블) 간의 관계를 표현한 그래프
- 많은 개발자들이 ERD으로 소통하기 때문에 ERD를 보고 해석할 수 있어야 한다.
- 하지만 DB 설계를 공부하는 입장에서 현재 꼭 익힐 필요는 없다. 설계에 적응되고 활용하여도 늦지 않다.
- 또한 만약 혼자 작업하는 프로젝트라면 작성하는 시간을 투자할 바에 그냥 개발하며 유지/보수하는 편이 좀 더 효율적일 수도 있다.
- ERD 표기 방법
DB 설계 및 반영
설계한 모델을 실제 DB에 반영하는 방법은 아래와 같다.
- SQL문(DDL) 활용하기
- DB 관리툴 (MySQL Workbench, dbeaver) 활용하기
- ORM 활용하기(JPA, TypeORM, Sequelize 라이브러리 활용)
공부 순서는 SQL → DB 관리툴 → ORM 을 활용하는 것이 좋다.
데이터 타입 (Data Type)
- 정수를 저장해야 할 때 INT → 계산에서 쓰는 값인지 아닌지 판별한다.
- 10억이 넘어가는 정수 : BIGINT
- 실수를 저장 : DECIMAL
- 문자를 저장 : VARCHAR(글자수)
- 6만이 넘어가는 문자를 저장 : LONGTEXT
- TimeZone을 고려하지 않고 날짜 데이터만 저장하면 되는 경우 (국내 서비스) : DATETIME
- TimeZone을 고려하면서 날짜 데이터를 저장해야 하는 경우 (해외 서비스) : TIMESTAMP
- True, False의 형태로 저장하고 싶은 경우: TINYINT(1)
- ** 현업에서 잘 사용하지 않는 데이터 타입 : CHAR, FLOAT, DOUBLE, TEXT
역정규화
- 흔히 과도한 정규화는 성능이 저하된다고 한다.
- 하지만 그래도 되도록이면 정규화를 지키는 것이 좋다.
- 성능 저하에 대한 논의는 정량화된 데이터를 기반으로 평가해야 한다.
정량화된 데이터를 바탕으로 정규화로 인한 성능 저하가 명백하여 어느정도 중복을 허용해야 하는 상황이 생긴다면 역정규화를 수행한다.
역정규화란 성능을 향상시키기 위해 정규화된 DB를 다시 중복을 허용하는 형태로 변경하는 과정을 뜻하며, 가급적이면 최후의 수단으로 사용하는 것이 좋다. 역정규화는 매우 제한적으로 사용해야 한다. 데이터 중복으로 인한 오류(이상현상)가 발생하지 않도록 많은 노력을 해야 한다.
REVIEW
해당 강의를 처음 듣는 목적은 짧은 러닝 타임 강의를 통해 알고 있던 개념을 정리하고자 했다. 짧은 강의를 통해 알고 있던 개념을 이해하기 쉽게 정리할 수 있어서 좋았으나 좀 더 깊은 지식들을 습득하기에는 한계가 있었다. (1~5 정규화, 역정규화 등) 하지만 본 강의를 통해 후행학습 과제를 정할 수 있게 되었고 실무에서도 보다 자신있게 DB 설계를 할 수 있겠다는 자신감이 생겼다. 해당 강의에 대한 만족도가 높아서 앞으로 다른 개념들도 박재성 강사님을 통해 학습하고자 한다.