술(述)/비교

natural key vs surrogate key

쪼랩전사 2021. 11. 11. 19:09
728x90

이 포스팅에서는 Primary Key가 무엇인지, 그리고 Primary Key를 지정하는 방법과 각 방법의 장단점에 대해서 살펴보겠다.

Primary Key(기본 키)

데이터베이스는 엔티티(entity)를 구분하기 위해서 Primary Key를 지정한다.

이 Primary Key는 엔티티를 구분하기 때문에 몇 가지 특징을 갖는다.

특징은 아래와 같다.

  • 유일해야 한다.
  • NULL이 허용되지 않는다.
  • 자동으로 색인이 된다.

이러한 Primary Key를 지정하는 방식은 두 가지가 있다.

Natural Key(자연 키)

Natural Key는 말 그대로 자연스러운 키이며, 유의미한 키이다. 키 자체가 가치가 있다.

 

누군가를 부를 때, 보통 이름을 부르게 되어있다. 만약, 이름이 겹치지만 않는다면 이름 자체가 훌륭한 Primary Key가 될 수 있다.

Surrogate Key(대체 키)

사실 Surrogate Key를 할당하는 방법은 많다. 하지만 여기서는 Integer 타입의 auto increment로 고정한다.

 

Surrogate Key는 대체하는 키이다. 무엇을? 바로 Natural Key를 대체한다. 하지만, 대체 키는 의미가 없다.

대체 키는 보통 Integer 타입을 가지며, 1부터 1씩 증가하며 Entity에 Primary key 값을 부여한다.

 

누군가를 부를 때, 3,984,712,934번아~ 하고 부르면 그 번호를 부여받은 사람이 즉각적으로 반응할 수 있을까?

아마도 거의 불가능할 것이다.

Natural Key vs Surrogate Key

자, 그럼 어떤 키 지정 방식이 더 훌륭할까? 위의 예시만 보면, Natural Key가 더 훌륭해 보인다.

하지만, 실제는 그렇지 않다. 각각의 키 지정 방식은 서로 장단점이 존재한다.

Natural Key

장점

  • 키 자체가 가치가 있다.
  • 비교적 Join 연산을 덜 수행할 수 있다.
  • 크기가 클 수 있으며, 크기가 변동될 수 있다.

단점

  • 바꾸기 어렵다. 사용자 요구사항에 따라 갑자기 Natural Key의 속성이 바뀌는 경우, 정말 타격이 크다.
  • 인덱싱하기 어려우며, 범위 연산의 경우는 더 오래 걸린다.

Surrogate Key

장점

  • 쉽다.[각주:1]
  • 엔티티의 적절한 키를 못 찾을 경우, 사용할 수 있다.
  • 인덱싱하기 쉽다. 범위 연산이 빠르다.
  • 크기가 작으며, 크기가 고정된다.

단점

  • 대부분의 경우에 Join 연산이 강제된다.
  • 키 자체는 가치가 거의 없다.
  • 정보 유출의 가능성이 있다.
  • 키 할당이 DB에 의존적이다.

해설

1. join

join은 테이블 간에 관계가 있을 때, 두 테이블을 결합하는 연산이다.

가정: 사용자와 아이템이라는 테이블이 있다.

가정 1: 사용자의 Primary Key가 사용자 이름이다.

  - 사용자의 이름만 알아도 사용자의 아이템들을 조회를 할 수 있다.

가정 2: 사용자의 Primary Key가 대체 키이다.

  - 사용자의 이름을 알더라도, 바로 사용자의 아이템들을 조회할 수 없다.

 

2. 크기

Surrogate Key는 Integer타입이므로 크기가 고정되어 있다.

Natural Key는 가변 문자열일 수도 있고, Integer타입 일 수 도 있다.

 

3. Natural Key가 아픈 경우

사람 테이블을 예로 들어보자.

처음에는 사람 이름이 겹치지 않아, 사람 이름을 Primary Key로 사용했다.

하지만, 사람 이름이 겹치는 경우가 생기면서, Primary Key를 주민등록번호로 바꾼다.

그런데, 주민등록번호가 사실 재발급이 가능하다는 사실을 알고 있는가? 가능하다.

다른 무언가가 필요하다.

그리고 바꾸는 과정 자체도 굉장히 힘들 뿐 아니라, 대부분의 경우에는 서비스를 내리고 작업해야 할 것이다.

 

4. 키 할당 주체

Surrogate Key는 DB에 의존적이다. 의미없는 key를 할당받기 위해 DB에 접속을 해야한다. 이를 손실로 보는 사람도 있고, 아닌 사람도 있는데, 필자는 손실이라고 생각한다.

새로운 엔티티를 프로그램에서 생성했는데, 일단 Key가 없는 상태로 만들고, 이를 DB에서 가져와야 한다? 논리적으로도 조금 이상하다.

 

5. 정보 유출

예를 들어보자.

어떤 사용자가 특정 사이트에서 두 개의 물품을 거의 동시에 주문했다.

이때, 주문 번호가 123번과 124번으로 부여받았다.

사용자는 ID가 순서대로 부여받는 다는 것을 눈치챘고, 한달 뒤 다시 주문해서 324번을 부여받았다.

그러면 사용자는 한 달에 200번의 주문이 있다는 것을 유추할 수 있게 된다.

이 것이 얼마나 위험한 일인지는 각자의 판단에 맡기겠다.

 

6. 범위 연산

사실 이건 조금 말이 안되긴 한다.

Surrogate Key 자체가 의미가 없는데, 이걸로 범위 연산을 해서 뭐해? 라는 생각이 들것이다.

맞다. 의미없다. 그래서 어느 사이트에서는 이것에 대해 열심히 싸우고 계신다.

 

마치며...

여기까지 Natural Key와 Surrogate Key에 대해 알아봤다. 아래는 DDD 배우시는 분들만 열어보기를 바란다. TMI이다.

 

DDD아시는구나!

더보기

필자는 요즘 DDD에 미쳐있다. 그런데 DDD에서 도메인 모델은 데이터베이스에 의존해서는 안 된다. 의존하지 않기 위해서 DIP으로 인터페이스 만들고 할당시켜도 되긴 하지만, 인터페이스 정보를 엔티티 생성하는 곳에 주입한다? 이것도 뭔가 이상하다. DDD에서 데이터 영속성을 지원하기 위해 Repository 패턴을 사용하는데, Repository 패턴에서 인터페이스는 정말 데이터의 저장과 복원에 대한 메소드만을 넣어야 한다. 그런데 저장할 때, ID를 부여받는다? 이것도 뭔가 이상하다. 또 Repository 인터페이스에 getNextID 같은 것을 만든다? Repository는 영속성을 위한 인터페이스이지, 저런 함수를 사용하는 곳이 아니다. 그래서 찾다 보니, 이런 걸 다시 공부하게 됐다.


  1. "히히, 걍 대체 키 써야지." 해도 대부분은 문제가 없다. [본문으로]