서버시스템구축실습 (3) 데이터베이스 모델링과 설계
지난 회차는 웹서버의 기본적인 구조의 node.js에 대한 설명.
웹서버에 대해 알아야 하는 데이터베이스 모델링. 중간발표에 모델링을 만들어 진행해야 함. 그러므로 2주차는 데베에 대해 복습하는 시간.
즉, 데이터베이스는 무엇이고 어떻게 진행해야 하는가?
1. 데이터 모델링의 개념
현실세계에 있는 개념적인 정보를 데베에 저장하고 싶은 것. 이때 저장하기 위해서 현실세계의 개념을 데베에 저장할 수 있도록 바꿔나가는 과정이 데이터베이스 모델링이다.
가장 먼저 ER을 그려야 한다. 현실세계의 개채들 사이의 관계를 한눈에 파악할 수 있도록 일종의 다이어그램을 그려야 한다. 그것을 개념적 모델링이라 부른다.
논리적 모델링은 ER까지는 현실 세계 개념들 사이의 관계만을 정리하는 개념적 모델링 단계였다면 이 단계에서는 하나의 데이터 모델링을 선정한다. 대표적인 예시는 관계 데이터 모델, 이외에도 여러가지 형태 - 계층적 형태, 객체 형태 등이 존재한다. 그중 하나를 선정한다. 관계 데이터 모델이 가장 많이 사용되는 모델이다. ERD를 관계 데이터 모델에 걸맞도록 변환하는 과정이 필요하다. 즉, 선정한 모델에 적합한 모델 구조를 만들어 내는 것이 중요하다.
그리고 생략되어 있지만 물리적 모델링이 하나 더 있다. 논리적 모델링에서는 관계 데이터 모델에 적합하게 테이블 형식으로 저장하고 기본키를 설정하며 제작했다면, 이후 특정 DBMS를 선정해서 MySQL, Oracle DB, PostgreSQL 등의 데이터베이스 매니지먼트 시스템 중 하나를 골라 (SQL을 사용하는건 공통, 그에 대한 확장판을 제공. 선정할 때 무엇을 지원하는지를 고려해서 선정해야 한다다) 고른 후에는 이 특정 DBMS에 적합한 형태로 변환해준다.
2. 데이터베이스의 설계 과정 - 데베 생명주기.
1) 요구사항 수집 및 분석: 데베를 만들기 전에 선행되어야 함. 사용자의 요구사항, 만드는 사람이 아니라 '사용할 사람'의 요구사항을 듣는 것. 어떤 데이터, 기능을 필요로 하는지, 어떤 방식 및 규모로 구축할지. 요구사항 명세서를 작성한다.
-> 그렇게 해야 모든 사람이 동의하지 않을 팀플 환경에서 자세히 작성한 요구사항 명세서가 있다면 팀원들의 일치가 용이하다.
2) 설계단계: 모델링 과정들이 전부 포함된다(아까 설명한). 요구사항 명세서를 바탕으로 개념적 모델링(ERD)를 작성하고, 논리적 모델링 - 데이터 모델에 맞게 변환 - 릴레이션 스키마를 도출하고 그 스키마를 가지고서 DBMS에 맞게 작업하는게 논리적 모델링이며, 그를 가지고 데이터베이스 스키마를 도출하는 것이 물리적 설계-모델링이다.
-> 중요, 만들다가 잘못되면 설계를 뒤엎어야 할 수도 있으니까.
3) 구현: 데이터베이스 스키마를 실제 DBMS에 적용한다. 이전 단계에서 잘 했으면 어렵지 않다.
4) 운영: 데이터베이스를 기반으로 소프트웨어 제공.
5) 감시 및 개선: 운영동안 데이터베이스 부하 등의 문제점을 확인, 개선. 인덱스를 새로 만들거나 하는 류의 방법을 통해 시스템을 개선한다.
3. 데이터 모델링 과정
팀프로젝트를 과정하면서 위의 단계들을 전부 진행할 것이다. 즉, 중간 보고서에는 설계까지의 내용들이 포함되어 있어야 한다. 이후 실제로 구축하고 그 위로 애플리케이션을 제작하게 된다.
1) 첫번째, 요구사항 수집 및 분석. 가장 우선시 되어야 한다. 사용자가 누구고, 데베의 용도가 무엇인지, 현실세계의 어떤 개채들의 정보를 데베에 저장하고자 하는지를 수집 및 분석한다.
2) 그를 가지고 ERD를 작성한다. 개념적으로 어떠한 핵심 개체들이, 그 관계들이 무엇인지 다이어그램으로 연결한다.
3)작성된 ERD를 가지고 관계 데이터 모델(이것으로 통일해 팀플 진행 예정)에 적합한 릴레이션 스키마로 변환한다. ERD를 RDB로 변환. 세부적인 내용들을 정하고 정규화 하는 작업을 통해서 이상 현상이 발생할 수 있기 때문에, 그것이 발생하지 않도록 한다(정규화의 목적).
4) 결과적으로 제대로 만들었는지 체크하기 위해 정규화 작업을 거치고 나면 릴레이션 스키마가 결과로 도출된다. 이 릴레이션 스키마는 어떤 R-DBMS로든 변환이 가능하다. 그것을 가지고 물리적 모델링을 구축한다.
처음에는 MySQL을 사용하려 했다가 유지보수가 힘들 것 같아서 상용 SQL인 OracleSQL로 변경했다고 한다면, 어떻게 되는가? 릴레이션 스키마를 재활용할 수 있는가? 논리적 모델링은 결국 관계 데이터 모델 기반의 RDBMS라면 릴레이션 스키마는 어떤 RDBMS든 적용이 가능하기 때문에 상관없다. 단, 물리적 모델링 과정에서는 매니지먼트 시스템 고유의 특성에 맞춰서 변경해야 한다.
물리적 모델링은 데이터베이스 매니지먼트 시스템에 의존적이다. (논리적 모델링은 데이터 모델에 의존적이라는 차이가 있다.)
각 단계의 굉장히 중요한 특성들에 대해 전반적으로 설명. 관계데이터 기반의 논리적 모델링 진행 시 릴레이션 스키마가 만들어진다 했는데 이는 관계 데이터 모델에 한정되어 있고, NoSQL등도 있다. 이것의 뜻은 Not Only SQL로 전면 부정이 아니다. 다른 것들도 지원을 하는 DBMS다. 일반적인 관계 데이터 모델을 따르지 않기 때문에 이 과정을 따르지 않고 다른 모델링 과정이 필요하다.
일단 우리는 가장 많이 사용하는 관계 데이터 모델을 사용해 실습하고 플젝을 진행할 예정이다.
01. 개념적 모델링
1. 개념적 모델링: 요구사항 명세서를 열심히 작성했을때, 개념적인 내용들 - 개체, 관계를 추출해 내는 과정.
그림을 보면 도서라는 개체, 고객이라는 개체가 있을 때 도서 이름, 출판사, 단가 등의 속성들이 있어 정보들이 있는 것. 고객 또한 이름, 주소, 번호 존재. 고객이 일반적으로 도서를 주문한다 - 개체들 사이에 주문이라는 관계가 존재한다. 이렇게 개념적으로 모델링을 하는 단계.
나와있는 그림은 ER 다이어그램, 엔티티 다이어그램, 객체 - 관계 다이어그램, ERD 다이어그램이라고 부른다.
그렇다면 어떻게 작성하는가?
2. ERD 다이어그램: 개체와 개체 간의 관계를 표준으로 나타낸 것. 각각 개채들에 대한 정보를 속성이라 생각하고 개체 사이에 있는 것을 관계라고 본다.
이때, 관계에도 속성이 달릴 수 있다. 1번의 그림에서 주문일자는 중요한 정보는 아니지만 고객과 도서라는 객체가 만나서 주문이라는 관계를 형성했을 때만 주문일자는 중요한 의미를 가지면서 속성으로 붙게 된다. 즉, 관계도 속성 보유가 가능하다.
그렇다면 개체란 무엇인가?
3. 개체: 사람, 사물, 장소, 사건 등이 개체가 전부 가능하다. 현실세계의 어떤 개념을 표현하는 일종의 정보(큰 단위의).
우리가 도서라는 개념이 있다면, 축구하는 여자/축구의 이해/축구의 역사 각각은 객체 - 엔티티라고 보면 된다. 각 도서가 각 객체가 된다. 이들을 하나로 정의하면 도서가 되고 이것을 엔티티 타입 - 객체 타입이라고 본다. 개체와 객체 타입이 혼용되어 사용되지만, 보통 객체라고 부를 때는 객체 타입을 의미하는 경우도 많다.
개체가 모이면 개체 집합이라고 표현한다.
- ER에서 객체를 표현할때는 직사각형으로 표현. 객체에는 두 종류가 있어서 구분. 강한 객체 타입, 약한 객체 타입으로 분류. 약한 개체 타입이 아닌 애들은 전부 강함. 강한 애들은 다른 애들의 도움 없이도 독자적으로 존재가 가능한 것을 말한다. 직원이라는 것을 독자적으로 존재할 수 있다.
약한 개체 타입은 상위 개체(강한 개체) 타입을 가진다. 예를 들어 직원과 부양가족은 어떤 관계인가? 부양이라는 관계가 있다. 직원은 가족을 부양하고, 이때 왜 부양가족이 의존해야만 하냐면, 회사 취업시 기업에서 부양가족에 따라 가족수당을 지급하기 때문에 부양 관계를 가진 약한 개체인 부양가족이 의미를 가진다. 즉, 어떤 직원의 부양가족. 어떤 직원의 배우자 혹은 퇴사한 직원의 부양가족은 아무 의미 없는 정보이다. 상위 객체에 굉장히 의존적으로만 존재할 수 있다.
- 속성으로 개체가 가진 성질을 나타낸다.
개체 타입이 도서일때 속성은 도서 이름, 단가, 출판사, 출판일 등이 존재할 수 있다. ERD에서 속성은 기본적으로 타원으로 표현한다. 어떤 개체가 가진 성질 - 속성을, 소속되어 있는 객체와 실선으로 연결해준다. 또한 키, 밑줄이 그어진 속성은 키 속성이란 의미, 도서라는 객체를 유일하게 식별할 수 있는 키의 의미를 갖는다.
아까 축구하는 여자는 도서의 이름이며, 이름으로 해당 도서들을 각각 구분할 수 있을때, 키 속성으로 구분할 수 있다.
- 속성은 어떤 종류가 있는가?
-> 일반적인 속성: 타원으로 표현. 속성의 이름만 주어진다.
-> 키 속성: 밑줄로 표현된다. 여러개의 개체 집합 중에 특정 객체를 유일하게 식별할 수 있게 하는 키인 경우.
-> 약한 개체의 식별자: 자체적으로는 아무 의미 없고 강한 객체가 있을 때에만 의미 있음. 자신만의 키를 갖지 못하지만 식별자라는 걸 소유. 약한 개체는 "식별자 + 강한 객체의 키 속성"이 합쳐져서 키가 된다. 약한 개체 내에서도 식별자 역할을 하는 게 존재해야만, 약한 개체 타입 내부에서도 구분이 있다. 예를 들어 아까의 부양가족에서도 배우자부터 자식이 존재할 테니까. 식별자는 밑줄이 점선이다(키와는 다르다).
-> 다중 값 속성: 이중 동그라미. 취미라는 속성이 있다면 자전거, 독서, 게임 등등이 전부 다 취미일 수 있다. 즉, 여러개를 취미로 가질 수 있다. 취미라는 속성의 값이 여러개가 되므로 - 하나의 객체에 대해서 들어갈 값이 수영, 자전거, 독서 이렇게 여러개가 들어갈 수 있을때, 다중 값 속성이라고 한다.
-> 유도 속성: 다른 속성으로부터 유도가 가능한 속성.
유도를 할 수 있다는 건 예를 들어 어떤 사람의 정보를 저장할때 생년월일을 저장해두면 생년월일로부터 오늘을 기준으로 만 몇살인지 만 나이를 계산할 수 있고, 만 나이를 속성으로 가질 필요가가 없어진다(생년월일을 가지고 있으면 만 나이를 유도할 수 있기 때문에). 유도속성으로 표현하고 BDMS에 유도가 가능하도록 표현하면 된다. 점선 타원으로 표현한다.
-> 복합 속성: 주소를 예를 들어 시, 동, 번지가 있는데 - 주소가 나누어져서 생겼는데 만약 주소라는 정보를 통채로 저장했다면, 서울시에 사는 사람만 추출하고 싶을때 저장하고 있는 정보 전체를 읽어서 찾아내야 한다. 이때 정보를 따로 저장해두면 데이터베이스에서 편히 찾을 수 있다! 그래서 하나의 속성인데 여러 부분으로 구성되어 있는 것을 복합 속성이라고 한다. 큰 타원 밑에 타원들로 구성이 된다. 주소라는 속성 위에는 객체가 있을 것이다. 즉, 속성 밑에 속성이 있는 것.
! 다중값 속성과 복합 속성 차이 이해 중요. 전자는 여러개의 값을 가질 수 있는 것, 후자는 하나의 속성이 여러개의 속성으로 구성되는 경우. 케이스에 따라 둘이 비슷한 특성을 가지는 경우도 있긴 하다.
- 키: 특정 '투플' (개체 타입, 개체1, 개체2, 개체3이 있을때 123 각각이 투플이라고 보면 된다. 아까의 도서 객체 타입에서 각가의 도서 이름들(축구, 야구, 농구)이 투플이었다. 정확히는 개체타입이 아닌 각각의 개체들. 표의 가로선들. 이때 도서이름이 유일하다면 그것을 키로 삼아 목표로 하는 투플을 찾을 수 있다.) 을 식별할 때 사용하는 속성/속성의 집합.
그런 키도 종류가 다양하다. 기본적으로 무엇이 있는가?
1) 슈퍼키: 릴레이션 내 투플을 식별할 수 있는 속성의 집합. 위에서 정의한 내용과 동일. 가장 큰 개념이다.
예를 들면, "속성의 집합"이라고 되어있기 때문에 고객번호, 주민번호, 핸드폰 각각이 있으면 속성을 정할수가 있다.
그 외에도 (고객번호, 이름)이 있으면 그 또한 식별이 가능하다. + (주민번호, 이름)도 가능. 이렇게 모든 투플이 있어도 식별 가능. 전부 합해서 슈퍼키라고 한다.
* 슈퍼키가 아닌 것. (이름)은 슈퍼키가 아니다. 이름만 있으면 동명이인이 있을 수 있다. 슈퍼키에 속하지 않는 이들도 존재한다.
2) 후보키: 슈퍼키는 집합이었지만 최소집합은 아니었다. (고객번호, 이름)에서 (고객번호)만 있어도 식별 가능하다. 이렇게 "최소집합"이라는 개념이 중요. 이때 최소집합은 개수의 개념이 아니다.
(이름, 주소)일때 투플을 식별할 수 있다고 생각해보자. 그렇다면 이것은 최소집합 조건을 만족하고 후보키인가? 만족한다. 둘 중 무엇을 하나 빼도 투플 식별이 성립되지 못하기 때문이다. 무언가를 더 뺄 수 없는 상태일 때를 최소집합이라 부른다. => 투플을 식별할 수 있는, 불필요한 것이 없는, 최소한의 집합인 경우.
3) 기본키/대체키: 후보키중에서 나오는 애들.
- 기본키: 후보키중에 선정된 키. 고객번호, 주민번호, (이름,주소)일때 고객번호를 기본키로 설정했다면 나머지는 대체키가 된다.
4) 대리키: 새롭게 만들어낸 키. 기본키를 억지로 만들어낸 것. 고객번호가 일종의 대리키.
고객번호가 없다고 가정했을 때, 주민번호를 기본키로 선정한 경우 - 데베를 조인할때 기본키를 가지고 조인한다. 이때 조인할때마다 주민번호를 활용한다면: 여기저기 사용되면서 보안적으로 문제가 발생할 수 있다.
고객번호는 새로운 고객이 만들어질때마다 고유한 고객번호를 생성하며 추가시켜주면 된다.
대리키는 기본키의 한 종류.
5) 왜래키: 참조를 할 때 사용.
고객과 도서라는 테이블이 존재하고 고객은 고객번호를 기본키로 선정, 도서는 도서번호로 기본키를 설정했다고 하자.
외래키는 무엇인가. 주문이라는 것은 고객과 도서의 관계이다. 1번 고객과 1번 도서의 관계가 무엇이냐 하면: 박지성이 축구의 역사라는 도서를 구매했을때 판매가격/주문일자를 기록하는 것. 이때 고객에 대한 정보/도서에 대한 정보를 참조하기 위해서 사용되는 게 "외래키"이다.
즉 외래키는 다른 테이블의 기본키를 가져와서 참조를 하는 데 사용되는 속성이다.
여기까지 개체/속성/키 설명.
- ER 다이어그램: 개체 사이의 연관성 설명.
개체 타입과 개체 타입 간의 연결 가능한 관계를 관계 타입이라고 하며, 관계를 전부 다 합치면 관계 집합.
도서외 고객 사이의 구매라는 관계, 학생과 학과 사이에 소속이라는 관계 같은 관계 표현.
- 관계 타입은 여러가지 유형으로 분류 가능.
-> 차수에 따른 분류: 관계 집합이 주어졌을 때 거기에 참가하는 개체 타입의 수를 차수라고 한다.
1) 학생 - 멘토링은 받는 사람도 학생, 하는 사람도 학생이기 때문에 개체가 하나로 표현됨: 1진 관계 = 순환 관계.
2), 3) 두개, 세개가 관계를 맺는것.
=> 몇개의 관계 집합이 관계를 맺느냐.
-> 관계 대응수에 따른 분류: 두 개체 타입 사이에 관계가 있을때) 실제로 참여하는 개별 개체의 수.
1) 한명의 사원이 한명의 컴퓨터 사용. 공유도 하지 않음: 일대일 관계.
2) 다대일/일대다 관계: 하나의 개체가 여러 개체와 대응. 예를 들어 학생은 학과 하나에만 소속, 학과에는 여러명의 학생 소속.
3) 다대다 관계: 하나의 학생이 여러개의 강좌 가능. 여러명의 학생들도 여러명의 강좌 가능.
개체 옆에다가 수를 표현.
-> 참여 제약 조건
앞에서 본 관계 대응수의 경우: 관계에 참여하는 최댓값을 기준으로 분류된다. 하나의 관계가 존재할때 그 관계에 참여하는 수가 최대 1개-1개여야 일대일이 된다. 이때 어떤 사원이 컴퓨터를 아직 받지 못한 상황도 가능하다.
참여 제약 조건은 최솟값이 어떻게 되는지를 표현하는 방법이다. 개체집합 내의 모든 개체가 이 관계에 참여를 하는지에 따라 전체참여/부분참여로 구분된다.
학생과 강좌 사이에 수강이란 관계가 존재하는데, 학생은 강좌에 부분참여한다(실선 한줄). 기본적으로 부분참여하고 전체참여는 특별한 상황이다. 수강이라는 관계에서는 학생은 참여할수도/안할수도 있는데, 강좌 측면에서는 수강생이 아무도 없다면 존재할수가 없다. 해당 강좌는 폐강된다! 모든 강좌는 수강이라는 관계에 전체참여를 한다 = 수강하는 학생이 강좌에 있어야만 한다.
결국 최솟값 기준으로 생각한다는 것. -> 강좌에는 최소 한명의 학생이 필요하다(1). 학생은 수강하는 강좌가 없어도 된다(0).
- 약한 개체 타입과 식별자(위에서 설명했다)
식별자 혹은 부분키. 가족이라는 약한 개체의 부분키인 이름은 밑줄로 표현된다. 직원이라는 강한 상위개체의 기본키인 직원번호와의 결합(조합)을 통해서 테이블이 만들어진다.
여기까지 개념적 모델링의 방법이었다.
02. 논리적 모델링
개념적 모델링에서 만든 ER 다이어그램에서 어떤 데이터 모델을 사용할지를 결정하고 그에 맞게 구현하는 과정. 우리는 관계 데이터 모델을 사용할 것이다.
논리적 모델링을 하게 되면 이런 식으로 릴레이션 스키마가 만들어진다. 위가 ER 다이어그램, 밑이 논리적 모델링의 결과.
- 변환을 어떻게 할 것인가? ERD -> 관계 데이터 모델 변환.
사상(맵핑) 사용. / 변환을 하는 단계는 순서대로 진행.
-> 1단계. 강한 개체 타입을 변환.
직사각형(이중X)(=강한 개체 타입)을 그대로 릴레이션으로 변환해준다. 그다음 사번과 이름이라는 속성을 넣어주고 기본키를 설정해준다.
-> 2단계. 약한 개체 타입을 변환.
강한 개체 타입 참조가 필요. 약한 개체 타입이 보유한 식별자 + 상위개체의 기본키를 외래키로 가져와서 (FK)(=왜래키) 두개를 합쳐다가 기본키로 지정한다. 강한 개체가 있어야지만 약한 개체는 의미가 있기 때문에 이렇게 포함한다.
- 관계를 변환하는 일반적인 방법에 대한 설명
관계 타입은 가운데에 있는 마름모이다. E1, E2라는 개체/ KA1, KA2의 기본키.
방법 1) 오른쪽을 그대로 두고, 툴을 만들때 반대편에 있는 것을 가지고 와서 외래키로 표현해준다. 이러면 E2가 외래키를 통해 E1을 참조한다.
방법 2는 방향만 반대로.
방법 3) 두개의 릴레이션을 통합함. KA1, KA2를 둘 다 기본키로 설정해버리고 합친다.
방법 4) 전체를 독립적으로 표현. E1, E2 그대로 놓고 R이라는 관계를 별도의 릴레이션으로 표현하고 - 각 개체의 기본키를 넣어준다. 그럼 그것을 참고해서 새로운 릴레이션을 만들 수 있다.
이것이 끝인가?
방법 5) 방법1/방법2를 동시에 적용함.
E1(KA1, A2, KA2)
E2(KA2, A4, KA1)
서로 왜래키를 교환하는 방식.
-> 3단계. 이진 1:1 관계 타입.
일대일인 경우 서로 교환하기도 하고 방법1/방법2를 적용할수도 있다.
-> 4단계. 이진 1:N 관계 타입.
n이 어디있느냐가 중요하다. 기본적으로는 1쪽에 있는 기본키를 n쪽으로 가져와서 왜래키로 가져와서 포함시키는게 기본이다. 이 경우, 학과는 그대로 있지만 - 학과코드 기본키를 외래키로 가져와서 학생에 넣는다.
거꾸로 하면 안된다! 항상 1쪽에 있는 애를 n쪽으로 가져와서 만든다. !!! 1=> N
-> 5단계. 이진 N:N 관계 타입
방법 4를 사용한다. 관계를 아예 새로운 릴레이션으로 만드는 것. 수업이라는 관계를 새로운 릴레이션으로 만들어 양쪽의 기본키를 가져와서 합쳐 기본키로 설정한다.
수업(사번(FK), 과목코드(FK)) <- 대리키(고유의 수업번호)를 따로 추가해서 걔를 기본키로 사용해도 OK.
수업(수업번호, 사번 (FK), 과목코드(FK)) 가능.
-> 6단계. N진 관계 타입
이 경우 많아지더라도 방법4를 사용하면 된다. 학생/강좌/강의실 그대로. 새로 수강이라는 걸 만들어서 학번, 강좌코드, 호실이라는 기본키를 왜래키로 가져오고 조합해서 기본키로 설정. 대리키를 추가해 지정해도 OK.
-> 7단계. 다중값 속성
취미가 여러개인 경우 같은 다중값 속성의 경우. 두가지 방법에 따라 처리.
방법2) 다중값 속성이 몇개가 들어갈지를 제한할 수 있는 경우(몇개가 들어가는지를 아는 경우): 속성을 분해해버릴 수 있다.
취미를 두개까지만 받는다고 한다면 학생(학번, 이름, 취미1, 취미2)로 설정. 취미2에 아무것도 들어가지 않는다며 NULL로 설정.
방법 1) 값의 속성을 알 수 없는 경우: 아예 새로운 릴레이션을 생성.
취미라는 릴레이션을 생성하면 학번으로 조회해서 001번의 취미: 게임, 0001번의 취미: 등산. 0001번의 취미: 스키 <- 로 계속해서 추가할 수 있다.
아예 속성으로 추가해서 만드는 경우에는 조회는 빠르지만, 매번 조인을 해서 원하는 정보를 뽑아내야 한다. 처리하는 속도 면에서는 방법 2가 더 좋고, 확장성 측면에서는 방법1이 더 좋다.
* 복합속성(주소 - 시, 동, 번지)의 경우 어떻게 할까?
방법2로 해결할 수 있다. 시, 동, 번지를 속성을 아에 추가해주면 된다.
- 기타 고려해야할 사항
1) 모든 관계는 독립적인 릴레이션으로 변환 가능.
꼭 정해진대로 할 필요 없다는 뜻. 모든 관계는 독립적인 릴레이션으로 제작 가능. 그러나 릴레이션이 너무 많아지면 항상 조인을 해야 하니까 속도 느려짐.
2) 순환 관계도 기본 규칙을 그대로 적용하면 된다.
순환관계에서도 일대다 가능. 1쪽에 있는 애를 n쪽으로 가져와서 외래키로 추가.
지금까지는 ERD를 관계 데이터 모델로 변환하는 방법이었다. 그렇다면 이걸로 끝일까?
잘 될 확률은 굉장히 낮다. 이상현상이 발생하는지를 확인해야 한다.
- 정규화
이상현상: 삭제이상/삽입이상/수정이상 존재.
삭제를 했을 때, 삽입을 했을 때, 수정을 했을 때 이상이 존재한다.
다음 테이블은 두개의 정보가 섞여있다. 학생번호 - 주소까지 학생정보, 강좌이름 - 강의실까지 강좌정보.
1) 삭제이상: 이때 장미란 학생 투플을 삭제한다고 하자. 그러면 강좌정보가 남아있어야 하는데 같이 날라가게 된다. 이것을 "연쇄삭제"라고 한다.
2) 삽입이상: 박세리라는 학생을 삽입하려고 한다. 그러나 강좌정보를 삽입하려고 한 것은 아니다. 기본기 제한조건 중 하나는 NULL값을 넣을 수 없다는 것이다. 강좌이름과 학생번호가 합쳐져서 기본기라고 가정한다면, NULL값을 넣을 수 없게 된다. 즉, 삽입이 불가능해진다.
3) 수정이상: 박지성 학생 정보를 업데이트하고 싶은데, 박지성 학생 투플이 두개가 존재한다. 이때 잘못 작성해 둘 중 하나만 반영된다면, 서로 다른 투플을 가지게 된다. 하나는 영국 맨체스터, 다른 하나가 대한민국 제주라면 어떤 데이터가 옳은지 알 수 없다 -> 데이터 일관성이 깨지게 된다. 실수로 SQL문을 잘못 작성하더라도 괜찮도록 설계 단계에서 노력해야 한다.
이것을 막기 위해 정규화를 사용한다.
- 함수 종속성/결정자라는 개념
어떤 속성 A의 값을 알면 다른 속성 B의 값을 유일하게 결정할 수 있을때: 속성 A는 B를 결정한다(=B는 A에 종속된다).
A -> B로 표기하고, A는 B의 결정자라고 한다.
어떤것들이 결정되는가? 학생번호, 강좌이름이 있으면 다른 것들을 결정할 수 있다. 학생이 정해지면 학과가 정해지고 강좌가 정해지면 강의실이 정해진다. (학생번호, 강좌이름)이 주어지면 다른 모든 속성들을 결정할 수 있다.
! 결정관계
학생번호 -> 학생이름
-> 주소
-> 학과
/ 학과 -> 학과사무실
결정자와 이상현상은 밀접한 관계가 있다.
- 이상현상과 결정자
이상현상은 한 개의 릴레이션에 두 개 이상의 정보가 포함되어 있을 때 나타난다. 기본키가 아니면서 결정자인 속성이 있을 때 발생한다!
-> 무손실 분해를 통해 해결한다.
기본키가 아니면서 결정자인 속성이 없도록. 분해를 할때 '무손실 분해'를 해야 성공적으로 정규화를 할 수 있다.
- 무손실 분해: 말 그대로 손실이 발생하지 않는 분해.
예를 들어 릴레이션 R을 R1과 R2로 분해할때, 즉 특강수강을 릴레이션 두개로 분해하고 싶을 때 어떻게 하면 좋을까?
종속성을 보면 학생번호가 교수를 결정하고 교수가 결정되면 특강이름이 결정된다.
방법1) R1, R2의 공통속성은 교수이다. 공통속성은 두 릴레이션 중 한 릴레이션의 키이기만 하면 된다(=후보키이기만 하면 된다).
교수는 특강이름을 결정하고 있기 때문에 후보키의 역할을 할 수 있다. 교수는 R2의 키이기 때문에 이는 무손실 분해이다. R1에서는 학생번호가 교수를 결정하고 있기 때문에 키는 아니다.
방법2) 공통속성은 특강이름이지만, 특강이름은 키가 아니다. 학생번호가 키이고, 교수가 키이다. 즉 무손실 분해 규칙을 만족하지 않는다.
이 경우, R3와 R4는 그렇게 문제가 없어 보이지만, 둘을 조인했을 때 원래의 릴레이션이 만들어지냐의 문제가 발생한다. 둘을 조인하면 의미없는, 기존에 있지 않았던 투플이 발생해버린다.
- 정규화: 릴레이션을 분해하여 이상현상을 없애는 과정.
단계적으로 진행. 높은 정규형일수록 이상현상이 줄어든다.
일반적으로는 보이스/코드 정규형 릴레이션(=3.5 정규형)까지 진행된다.
릴레이션 분해를 많이 할수록 조인을 많이 하고 -> 성능상의 문제가 발생하게 된다. 그래서 정규화를 더 많이 할수록 오류가 줄어든다.
- 제 1정규형
모든 속성값이 원자값을 가지기만 하면 된다. 원자값=다중값 속성의 반대. 다중값 속성이 아니기만 하면 된다.
고객취미들은 다중값 속성이다. 제 1정규형을 반영하면 다음으로 나뉜다.
ERD를 릴레이션 스키마로 변환하는 과정을 거쳤다면 이미 했을 것. 당연히 만족하고 있을 조건 - 가장 기본적인 조건.
- 제 2정규형
제 1정규형 기본 충족을 베이스로 깔고 간다.
기본키가 아닌 모든 속성이 기본키에 "완전 함수 종속"이 되어야 한다. 기본키에 대해서 "부분 함수 종속"이 발생하면 안 된다.
예를 들어 학생번호와 강좌이름이 기본키라면, 이 두개는 성적과 강의실을 결정한다. 그리고 이 둘이 합쳐져야 성적은 의미가 있다. 그런데 강의실은 강좌이름만 주어져도 결정될 수 있다.
즉 실제로는 기본키를 구성하는 일부 속성인 강좌이름이, 혼자 강의실을 결정하고 있다. 이것을 "부분 함수 종속"이라고 한다. 기본키를 이루고 있는 부분집합이 결정자 역할을 하는 것.
-> 이를 방지하기 위해 문제를 일으킨 대상을 분해를 하면 된다.
강의실만 따로 분리된다.
이때 무손실 분해가 됐는지를 확인한다. 둘의 공통속성은 강좌이름이며 강좌이름은 강의실에서 키의 역할을 하고 있다=무손실 분해이다.
각각 따져보면 둘 다 조건을 만족하게 됐다. 기본키에 완전 함수 종속을 하게 되었다.
- 제 3정규형
릴레이션 R이 제 2정규형을 만족하는 것을 기본으로 한다.
이행적 종속이 있으면 안된다. 기본키가 아닌 속성이 비이행적으로 종속되어야 한다.
이행적 종속이란: A -> B, B -> C가 성립할 때 A -> C가 성립되는 함수 종속성.
학생번호를 기본키로 잡더라도 아무 문제는 없어 보인다. 간접적으로 수강료가 결정되기 때문에.
하지만 이것을 "이행적 함수종속"이라고 하며 없애야 한다. 없애기 위해서는 분해하면 된다.
학생번호 -> 강좌이름, 강좌이름 -> 수강료로 분해.
이행적 함수종속이 없어졌기 때문에 조건 만족.
- BCNF: 보이스 코드 정규형. 3.5NF
당연히 제 3정규형을 만족한다.
함수 종속성 X -> Y가 성립될 때, 모든 결정자 X가 후보키여야 한다.
기본키가 학생번호/특강이름이다. 이때 교수는 키가 아닌데 특강이름을 결정한다.
후보키도 아닌데 결정을 하면 안된다: 분해를 해서 해결.
학생번호 -> 교수 결정. 교수 -> 특강이름 결정.
둘의 공통속성은 교수이다. 이때 특강교수에서는 교수가 특강이름을 결정하고 있기 때문에 무손실 분해이다.
즉, 분해를 무손실 분해가 되는 방향으로 분해해야 한다.
- 물리적 모델링
논리적 모델링을 통해 릴레이션 스키마를 만든다. 그것을 특정 DBMS에 저장하기 위해 물리적 구조를 정의하고 구현한다 .테이블을 만드는데 테이블 이름을 정하고, 데베에 저장되는 타입을 설정하고, 각각의 사이즈도 정의한다. 이중에 어떤게 기본키가 되는지도, 외래키는 무엇인지도 정의한다.
즉 특정 DBMS에 저장되기 위한 구조를 정의/구현하는 것.
물리적 모델링 구현이 완료되면 DB 구축은 손쉽다.
여기까지가 중간보고서에 담겨야 할 내용. 구체적인 중간보고서 양식은 차후 설명하겠지만 오늘 배운 내용은 보고서에 포함되어야 할 내용이다.