Database Design - Logical and Physical Design (4)

3 minute read

Overview

개념적 설계가 완성되었다면 이를 논리적(logical) 및 물리적(physical) 설계로 변환해야 한다. 주로 DBMS가 이 시점쯤에 정해진다. 엄격히 말해 논리적 설계와 물리적 설계는 서로 다른 단계로 나뉘어지지만 대체로 한 단계로 병합된다. 대부분의 최신 DBMS들이 디스크에서 논리적 레코드와 물리적 레코드를 1:1으로 매칭시키기 때문에, 두 설계가 오버랩된다.

각 개체(entity)는 데이터베이스 테이블이 될 것이고 그것의 attribute들은 테이블의 필드가 될 것이다. 외래 키의 경우, DBMS가 이를 지원한다면, 혹은 설계자가 이를 구현하고자 한다면 생성되면 된다. 만약 관계가 mandatory하다면 외래 키는 NOT NULL로 정의되어야만 하고, 만약 optional하다면 외래 키는 null값을 가질 수 있다.

예를 들어 이전 글의 예제에서 invoice line-to-product 관계로 인해 invoice to line 테이블에서 product code 필드는 외래 키가 된다. Invoice line은 product를 가져야하기 때문에 NOT NULL이 될 수 없는 것이다.

테이블을 normalizing하는 것은 데이터베이스 설계에서 매우 중요한 프로세스이다. 이를 통해 데이터 중복을 방지하고 데이터 무결성을 높일 수 있다. 이에 대해서는 별도의 글에서 다루도록 하겠다.

처음 데이터베이스 설계를 하면서 겪을 수 있는 흔한 에러에 대해 나열해보았다. 신중하게 entities 및 attributes를 식별하고 데이터를 normalize하였다면 아래 에러들을 피할 수 있을 것이다.

  • 관련되지 않은 데이터들을 서로 다른 테이블에 보관하자!
    • 스프레드시트를 주로 사용하는 사람들이 이런 실수를 저지른다. 왜냐하면 그들은 모든 데이터를 하나의 2차원 테이블로 보는 것에 익숙하기 때문이다. 관계형 데이터베이스는 더욱 파워풀하기 떄문에 이런식으로 한꺼번에 저장할 필요가 없다.
  • 계산할 수 있는 값들은 저장하지 말 것!
    • 예를 들어 세 개의 숫자가 있다고 치자: A, B, 그리고 A*B. 마지막 곱의 값은 저장하지 말자. 공간만 낭비하고 필요 시 쉽게 계산할 수 있다. 그리고 데이터베이스 유지보수가 더 어려워 진다 - 만약 A를 바꾸면 곱의 값들도 다 바꿔야 한다. 바로 쉽게 계산할 수 있는데 왜 공간을 낭비하는가?
  • 설계한 것이 우리가 분석한 모든 조건들을 다루는가?
    • ERD를 급하게 그리다 보면 조건을 빠트릴 수도 있다. ERD에서 이해관계자들은 없는 룰을 발견하기 보다는 잘못된 룰을 발견하기가 더 쉽다. 비즈니스 로직은 데이터베이스 로직만큼 중요하고 빠트릴 확률이 높다. 예를 들어 sale에 대해서 관련된 고객이 없으면 sale이 존재할 수 없다는 것을 발견하기 쉽다 (데이터베이스 로직). 하지만 $500 이하의 sale에 대해서 고객은 다른 승인된 고객이 추천하지 않는 이상 승인될 수 없다는 조건이 적용되었는가? (비즈니스 로직)
  • 필드 이름이 될 attribute들이 잘 선택되었는가?
    • 필드들은 명확한 이름을 가져야 한다. 예를 들어 surnamefirst_name 대신 f1f2를 사용한다면 타이핑 시간을 줄이더라도 오해를 불러올 수 있다. 또, 서로 다른 필드 값들에게 동일한 이름을 쓰면 안된다. 만약 여섯 개의 테이블이 code라는 primary key가 있다면, 인생이 불필요하게 힘들어진다. 그렇게 하지 말고, 각 테이블에 대해 sales_code 혹은 customer_code와 같이 명시적인 이름을 쓰자.
  • 너무 많은 관계를 만들지 말자
    • 시스템에 있는 거의 모든 테이블이 상식적으로는 다 관계를 가질 수는 있다. 하지만 그럴 필요는 없다. 예를 들어 테니스 선수는 어떠한 스포츠 클럽에 속하고, 스포츠 클럽은 어떠한 지역에 속한다. 따라서 테니스 선수 또한 지역에 속한다. 그러나 이 관계는 스포츠 클럽을 통해 도출해낼 수 있기 때문에 또 다른 외래 키를 추가할 필요가 없다. (특정 쿼리에 대한 성능 개선을 위한 경우를 제외하고는) Normalizing을 통해 이러한 문제를 해결할 수 있다. 심지어 성능을 최적화할 때도, normalize한 후에 denormalize하는 것이 normalize를 안 하는 것보다 대체로 더 낫다.
  • 단, 필요한 모든 관계들은 다 고려되었는가?
    • ERD의 모든 관계가 테이블 구조에 공통 필드로 나타나는가? 모든 필요한 관계를 포함하였는가? 모든 many-to-many 관계들이 두 개의 one-to-many + intersection entity 관계로 분해되었는가?
  • 모든 제약 조건들을 나열하였는가?
    • 제약 조건이라함은, 예를 들어 성별이 male이나 female밖에 될 수 없는 것, 학생들의 나이가 20살 이하여야 되는 것, 이메일 주소가 최소 한 개의 @ 기호가 있어야 하는 것들이 있다. 이러한 것들을 당연하게 여기지 말자. 시스템 개발의 어떠한 시점에서는 구현해야할 것이고 이러한 제약 조건들을 나열하지 않고 할 경우 아예 잊어버리거나 다시 돌아오게 될 수도 있다.
  • 너무 많은 데이터를 저장하려고 하진 않는가?
    • 고객이 온라인 뉴스레터에 구독하기 위해 그들의 눈 색깔, 최애 생선, 할머니와 할아버지 성함을 등록할 필요가 있을까? 이해관계자들은 때때로 그들의 고객들로부터 너무나 많은 정보를 원한다. 유저가 조직 밖에 있으면, 설계 단계에 참여할 기회가 주어지지 않는다. 그러나 고객이 항상 우선시 되어야 한다. 그리고 모든 데이터를 캡쳐하기 위해 걸리는 시간과 난이도도 고려해야 한다. 또, 데이터가 데이터베이스 속도에 미치는 영향도 고려하자. 큰 테이블들은 일반적으로 접근 속도가 더 느리고, 불필요한 BLOB, TEXT 및 VARCHAR 필드들은 레코드 및 테이블 단편화(fragmentation)을 초래한다.
  • 분리되어야 할 필드들을 합치진 않았나?
    • 초보들이 흔히 하는 실수가 first name과 surname을 한 개의 필드로 합치는 것이다. 예를 들어 John Ellis나 Alfred Ntombela처럼 저장하면 나중에 이름을 알파벳 순으로 정렬할 때 까다롭다는 것을 알게된다. 뚜렷하게 차이나는 것들은 별개로 저장하자.
  • 모든 테이블이 primary key를 갖고 있는가?
    • 만약 그렇지 않다면 매우 매우 중요한 이유가 있어야 할 것이다. 그렇지 않으면 어떻게 고유한 레코드를 빠르게 식별할 것인가? 인덱스를 통해 접근하는 것은 속도를 대단히 높여주고, 저장공간 또한 작기 때문에 오버헤드가 크지 않다. 또한, 이미 존재하는 필드를 primary key로 쓰는 것보다 새로운 필드를 생성하는게 좋다. 현재 데이터베이스 기준으로 first name과 surname이 고유할지라도 나중에는 아닐 수 있다. 시스템 레벨에서 정의된 primary key를 생성함으로써 uniqueness를 항상 보장할 수 있다.
  • 외래 키들이 올바르게 위치했는가?
    • One-to-many 관계에서 외래 키는 many 테이블에 나타나고 그와 연결된 primary key는 one 테이블에 나타난다. 헷갈리지 않도록 주의하자. 어떠한(one) 섬(primary key)에 여러 명의(many) 외국인들(foreign keys)이 여행을 온다고 생각하자.
  • Referential integrity(참조 무결성)이 보장되는가?
    • 외래 키들은 더 이상 존재하지 않는 테이블의 primary key와 관계를 가지면 안된다.

Updated:

Leave a comment