Primary key(이하 PK)는 한 개 혹은 여러 개의 칼럼으로 테이블 내의 각 행들을 구별하기 위한 목적을 갖고 있다.

 PK는 그 자체만으로 Unique 하며 만약 여러 개의 Column이 PK로 묶여 있다면, 해당 값들의 조합이 반드시 Unique 해지게 된다.

 PK는 NULL 값을 갖을 수 없고(NOT NULL), Unique key라는 특징을 갖게 된다. 단순하게는 NOT NULL & UNIQUE == PK 라고 생각하면 편하다. 물론 좀더 디테일하게 보자면 차이가 있다.


 MySQL에서는 Int 작업이 빠르기 때문에 PK는 Int형으로 지정하는 것이 좋다. 


 Unique Key(Unique index)는 value의 값을 유일하게 만드는 column의 제약으로 PK와는 조금 다르게 NULL값이 가능하며, 역시 여러 개로 묶어서 Combination Index 를 만드는 것이 가능하다.


 * MySQL에서 Key와 Index는 동의어이다. (PRIMARY KEY 가 아니라 Key 가 Index와 동의어이다. 물론 PK 는 Index로 취급되긴 한다.)

 Unique Key 와 PK 의 차이점은, NULL 허용 여부와 의미 상의 차이가 있다. PK 로 지정된 Column 들은 Table 의 Row 를 구분하는 대표 값들이라는 Identity 를 갖지만, Unique Key 는 그보다는 좀더 제약(Constraint) 에 가깝다. 물론 "Unique" 해야 하기 때문에 구분하는 대표값으로 사용해도 무방하지만, PK 처럼 테이블의 대표값라고 취급하는 것은 위험하다.


 MySQL PK 지정 예시. (생성시)


(ex) Create table t(

id int not null, 

name char(10) not null, 

contents text, 

primary key(id, name));


 MySQL PK 추가 예시. (테이블에 추가)


(ex) Alter table 테이블 Add Primary key(칼럼)


 Key 값 조회하는 방법 예시.


(ex) Show Keys from 테이블



 물론 복잡한 DB 쿼리를 다루었던 프로젝트에서는 데이터 무결성을 효율적으로 관리하던 Constraint 를 본적이 있었지만, 경험상 실무에서 Unique Key Constraint 보다는 주로 PK로 값 연결하는 일이 많았다. 

 Unique Key Constraint 는 데이터 무결성에 있어서 좋은 도구이기는 하나... Constraint 도구들이 실 서비스에서도 유용하다고 볼순 없기 때문에 PK 만큼 유용하게 사용되지는 않는 듯 하다.





 처음 학부생 때 공부를 위해서 혹은 실무에서 관계형 데이터 베이스를 접하고, 직접 설계하는 일은 쉽지 않다.

많은 DB 테이블들이 직관적으로 나타나있고 관계 역시 이해하기는 어렵지 않지만 이를 구성하고자 한다면 성능, 데이터의 정합성, 중복 배제 등 고려해야할 내용은 많다. 물론 그걸 다 잘하기는 매우 힘들며, 비즈니스 특성에 따라 트레이드 오프를 감안하여 작성하게 된다. ^^;;

 처음 DB 설계를 해보려는 이들에게 이번 정리 내용의 포스팅은 큰 도움이 될 수 있다.


 * RDB 설계 시작하기 5가지 단계


(1) DB의 목적을 명확히 한다. (Define the purpose of the DB)


(2) 수집한 데이터를 적절히 나눌 수 있는 기준이 될 Primary Key 를 구성한다.


(3) 테이블 간의 관계를 구상한다. 가장 쉬운 관계의 형성은 PK를 중심으로 생각하는 것이다. 


- One to many : Parent 테이블의 모든 value는 많은 Child table의 Record를 가질 수 있으나 Child table의 모든 Value는 Parent table에서 단 하나의 Record에 대응되어야 한다.


- Many to many : Many to many의 관계는 일반적으로 다수의 one to many 관계들로 이루어질 수 있어야 한다.


- One to one : 주로 동등한 레벨의 정보에 대한 Column 분리 용도로 사용된다.


(4) Refine and Normalize the Design(정규화)


 Column의 추가나 Optional data 처리를 위한 table 분리 등.


- 1NF : 기본적으로 필요한 속성들을 하나의 entity로 모아놓고 하나의 속성을 UID로 선정했다면 0NF 상태이고, 여기서 Repeating group을 제거하면 1차 정규화 형식이라 한다.


- 2NF : 속성들이 PK의 일부에 대해서만 종속적이라면 이 Part key dependency를 제거하여 2NF 형식이 된다.


- 3NF : 2NF에서 Key가 아닌 다른 속성에 종속적일 때 Inter-data dependency라 하며 이를 제거하면 3NF 형식이 된다.


- BCNF : Key 내의 속성이 key 내의 다른 속성에 종속적이라면 Inter-key dependency라 하며 제거하면 BCNF 형식이 된다.


(5) Denormalize : 순수히 성능만을 위한 기법이다.

- Comined table : 자주 조인하는 테이블의 경우 조인 성능부하를 없애기 위해 미리 Join된 형태로 table에 합침. 그럴 수 없는 경우 Join overhead는 Index나 SQL Plan을 조정한다.


- Derived data : 계산해서 얻을 수 있는 값을 굳이 칼럼으로 따로 빼준다.


- Artificial key : 적절한 PK가 없거나 인덱싱이 힘든 경우 간단한 AK를 만들어 해결하고 PK column은 일반속성화 한다. (예를들어 굳이 나뉘어져있지 않은 기수 번호를 인공적으로 Key로 만들어주어 부여하고 이를 인덱싱하여 성능을 개선한다.)


- Denormalization 의 예시. 유저 정보 테이블 id, name, address. 유저 성적 테이블 id, score. 두 테이블의 조인이 빈번하다면 두 테이블을 합칠 수 있음. Id, name, address, score.



 * 추가적으로 좀 더 자세한 설명이 필요하다면 다음 링크가 정말 잘 정리되어있다.  http://www.ntu.edu.sg/home/ehchua/programming/sql/relational_database_design.html






 RDB에서 관계를 맺는데 있어서 식별관계(Identifying Relationship)와 비식별관계(Non-Identifying Reltationship)가 존재한다.

정확히는 RDBMS에서 나누는 관계가 아닌 ER Diagram 상에서 논리상 나누는 개념이며... 굉장히 헷갈린다.


 Identifying Relationship 은 부모 테이블의 기본키 또는 복합키가 자식 테이블의 기본키 또는 복합키의 구성원으로 전이되며, 관계는 서로 종속되게 된다.


 예를 들어서 B라는 테이블의 FK child A 테이블의 PK를 참조한다면 Identifying Relationship에서 B테이블은 A 테이블에 종속이 되어서 A값이 없으면 B값은 홀로 의미를 갖지 못하는 관계가 된다. 아래의 테이블을 보자


<학생 정보를 기록하는 TableA 와 학생 성적을 관리하는 TableB>


위의 테이블에서 tableA는 학생들의 정보를 기록하는 테이블이고, tableB는 학생들의 과목별 성적을 기록하는 테이블이 된다.

TableA와 TableB는 똑같이 studentId를 PK로 갖고 있으며, TableB 에서 studentId 가 없다면 TableB는 독립적으로 존재할 수 없는 정보가 된다. 이때, 우리는 학생의 성적은 학생에게 종속되어 있다는 사실을 기반으로 생각하기 때문이다. 이러한 Strong coupling 에 대한 관계가 Identifying Relationship 이다. 


 반면에 Non-Identifying Relationship 은 자식 테이블의 일반 속성(Attribute) 그룹의 구성원으로 전이되는 비식별관계로부모는 자식의 부분적인 정보만을 표현함을 의미한다위의 예에서 Non-Identifying Relationship 의 경우 B테이블의 값은 A FK의 관계를 맺고 있긴 하지만 독립적으로 존재할 수 있어야 한다.(즉, FK가 B테이블의 PK가 되어선 안된다.) 이제 위의 테이블을 Non-identifying 한 관계로 바꾸어보자.


<학생 정보를 기록하는 TableA 와 학생 성적을 관리하는 TableB>


변경된 테이블에서 TableB는 더이상 studentId를 키로 갖지 않는 대신 별도의 독자적인 subjectId를 키로 가진다. 그리고 학생정보를 기록하는 TableA가 이를 참조하는 방식으로 변경되었다. TableB의 subjectId는 특정 성적의 기록이 되며, 성적의 기록을 모아둔 성적 기록부가 된다. 학생기록부(TableA)에서 성적기록 태그(subjectId)를 찾으면 이제 해당 학생의 성적 정보가 완성된다. 즉, 두 테이블은 서로가 없이도 유효한 정보를 나타낼 수 있다.


 이해를 돕기 위해 좀 더 편한 예시를 들어보자, 가령 책과 독자와 같은 정보의 경우는 Non-Identifying 관계이며, 독자가 없어도 책은 존재할 수가 있다. 하지만 저자와 책의 경우는 저자가 없는 책이 있을 수 없으므로 Identifying 관계라고 할 수 있다.



 * 관련되어 헷갈린 개념으로 Optional 과 Mandatory라는 개념이 있다. 이는 Non-identifying Relationship에 적용되는 내용으로, 참조하는 Foreign Key가 Null이 될 수 있는가에 대한 내용이다. 가령 위의 예시에서 어떤 학생이 어떤 과목의 시험성적도 갖고 있지 않다면 subjectId는 NULL이 될 수 있다. 학생의 성적 기록이 없기 때문이다. 이 때를 Optional 하다고 하며, NULL이 허용이 안되는 상황, 모든 학생이 입학시험은 적어도 봐야한다고 하면 subjectId는 NULL이 될 수 없다. 이 때를 Mandatory 하다고 한다.


서두에 언급했듯이 이는 ERD 를 그릴때 고려되는 개념이기 때문에 어떻게보면 추상적인 개념이라고 할 수 있다. 실무에서 ERD를 그릴 때 모른다면 실수로 잘못된 커플링을 갖거나 NULL이 허용되는 상황에서 NULL이 허용되지않는 관계가 생겨날 수도 있기 때문에 알아둘법한 지식이다.




+ Recent posts