데이터베이스

FK(외래키)를 주식별자인 기본키(PK)로 꼭 넣어야할까? 아니면 비식별자로 넣어야할까?

묠니르묘묘 2024. 2. 5. 15:48

우선 간단한 개념부터 살펴보자.

 

🚀 식별자(Identifier) 개념

  • 하나의 엔터티(entity)에 구서된 여러 개의 속성 중에 엔터티를 대표할 수 있는 속성
  • 하나의 엔터티는 반드시 하나의 유일한 식별자가 존재
  • 논리 데이터 모델링 단계에서는 '식별자', 물리 데이터 모델링 단계에서는 '키(key)' 라고도 불림

 

🚀 식별자 분류와 특징

  • 엔터티 내에서 대표성을 가졌는가? 주식별자 or 보조식별자
  • 엔터티 내에서 스스로 생성 되었는가? 내부식별자 or 외부식별자
  • 단일 속성으로 식별 되는가? 단일식별자 or 복합식별자
  • 업무적으로 의미가 있던 식별자 속성을 대체하여 새롭게 만들었는가? 본질식별자 or 인조식별자

(위 질문에 대한 답이 맞으면 왼쪽 아니라면 오른쪽)

 

 

📚 주 식별자(Primary Identifier) 특징

  • 유일성 : 주식별자에 의해 엔터티 내에 모든 인스턴스들이 유일하게 구분됨
  • 최소성 : 주식별자를 구성하는 속성의 수는 유일성을 만족하는 최소의 수
  • 불변성 : 주식별자의 값은 변하지 않는 것
  • 존재성 : 주식별자가 지정되면 반드시 값이 존재 (Not Null)

 

📚 외부 식별자(Foreign Identifier) 특징

  • 주식별자의 특징과 일치하지 않고, 참조무결성 제약조건(Referential Integrity)에 따른 특징 있음
  • 다른 엔터티와의 관계를 통해 자식 쪽 엔터티에 생성되는 속성
  • DB 생성 시, 외래키(Foreign Key) 역할

 

🚀 식별자 관계(Identifying Relationship)

  • 부모로부터 받은 식별자를 자식엔터티의 주식별자로 이용하는 경우를 식별자 관계라 함
  • 주식별자의 특징을 전부 가지고 있어야 하며, 부모의 식별자가 손자까지 계속 이어지는 점이 있음
  • 반드시 부모엔터티가 생성되어야 자식엔터티가 생성되는 경우

 

🚀 비식별자 관계(Non-Identifying Relationship)

  • 부모엔터티로부터 속성을 받았지만 자식엔터티의 주식별자로 사용하지 않고, 일반적인 속성으로 사용하는 경우
  • 부모엔터티의 식별자가 필수가 아니므로, 부모 없는 자식이 생성될 수 있음
  • 부모-자식 간에 관계가 있지만, 부모 먼저 소멸될 수 있음
  • 부모의 식별자를 자식 식별자로 사용해도 되지만, 별도의 주식별자를 생성하는 것이 유리할 때 사용

 

🤔 식별자 관계로만 설정한다면?

  • 개발 복잡성과 오류를 유발하는 요인이 될 수 있음
  • 지속적인 식별자 관계를 연결한 데이터 모델의 PK의 개수는 데이터 모델의 흐름이 길어질수록 증가
  • 조인할 경우 SQL 구문의 WHERE 절이 매우 길어짐
  • 조인관계를 누락할 가능성이 높아짐

식별자 관계로만 이루어졌을 때

위와 같은 규칙처럼 자식 엔터티가 많아질수록 식별자는 1개씩 추가된다.

 

🤔 비식별자 관계로만 설정한다면?

  • 불필요하게 부모엔터티까지 찾아가면서 자식엔터티에서 조회할 경우가 생김
  • 즉, 불필요한 조인이 다량으로 유발될 가능성
  • SQL 구문이 길어지면서 복잡성이 증가하고, 성능이 저하될 가능성

비식별자 관계로만 이루어졌을 때

 

간단하게 손자 테이블에서 부모번호가 '1'인 데이터를 조회할 경우 SQL문은 다음과 같다.

SELECT *
FROM 부모 A, 자식 B, 손자 C
WHERE A.부모번호 = B.부모번호
AND B.자식번호 = C.자식번호
AND A.부모번호 = '1';

 

만약 식별자 관계였다면 아래와 같다.

SELECT *
FROM 손자
WHERE 부모번호 = '1';

 

이 상황에서 성능과 개발용이성 측면은 식별자 관계가 더 간단하다.

따라서 일정한 규칙을 가지고 데이터 모델링을 하는 기술이 필요하다.

그럼 어떤 규칙을 가지고 해야할까?

 

🚀 비식별자관계 선택 프로세스

기본적으로 식별자 관계로 모든 관계가 연결되면서 아래 조건에 해당할 경우 비식별자 관계로 조정한다.

 

비식별자 관계 선택 방법

🎯 식별자관계 고려사항

  • 반드시 부모엔터티에 종속
  • 자식 주식별자 구성에 부모 주식별자 포함 필요
  • 상속받은 주식별자속성을 타 엔터티에 이전 필요

🎯 비식별자관계 고려사항

  • 약한 종속관계
  • 자식 주식별자 구성을 독립적으로 구성
  • 자식 주식별자 구성에 부모 주식별자 부분 필요
  • 상속받은 주식별자 속성을 타 엔터티에 차단 필요
  • 부모쪽의 관계참여가 선택관계 (부모 없이 자식이 먼저 생성되는 경우)

 

📝 개인적인 생각

지금까지 다룬 내용은 "SQL 전문가 가이드" 도서를 통해 얻은 지식이다.

이 도서를 통해 얻은 지식을 바탕으로 식별자에 대한 고민을 하게 되었다.

"무조건 비식별자로 두고, 모든 테이블에 시퀀스와 같은 일련번호를 부여한 PK(기본키)를 만드는 것이 좋을까?"

"상황에 따라 다르지만 아니다" 고 말할 수 있다.

 

대학교 DB 교수님은 "의미있는 속성들로 기본키를 구성하되, 없다면 시퀀스(더미키)를 사용해라"고 말씀하셨다.

실무에서는 회사마다 다르지만 시퀀스(UUID, TSID, 일시 등)를 사용하여 DB 구조를 유연하게 만드는 곳도 있었고, 이는 다양한 기업의 테크 블로그에서 확인할 수 있었다.

이렇듯 ERD 설계에 대한 접근 방식이 다양하지만 크게 개발자 입장과 DBA 입장이 있었음을 확인할 수 있었다.

 

내가 개발했던 프로젝트는 시퀀스를 이용하고 비식별자로 두었다.

이러한 접근 방식의 장점으로는 아래와 같다.

1. DB 구조의 유연성으로 미래의 변화에 대응하기 쉽다

    → 복합키를 가진 두 테이블 사이에 중간 테이블을 만들어야 하는 경우

    → 주민등록번호와 비슷한 속성과 복합키로 이루어졌으나 정책상 변경해야하는 난감한 경우

    → 비즈니스를 의존하지 않는 시퀀스라면 위 두 상황에서 자유롭게 변경 가능

2. 식별관계로 이루어진 테이블이 자식 테이블로 전파하면서 기본키가 증가하는 특징이 없음

3. 복합키로 된 테이블은 쿼리 조건문에 따라 인덱스가 제대로 사용되지 않을 가능성

4. 비즈니스 로직상 제약조건들이나 쿼리 성능개선에 유연한 대처

 

단점으로는 불필요한 JOIN과 성능문제, 더미값, 중복데이터 등이 있다.

역설적으로 더미키는 비즈니스에 의존하지 않는 키이므로 '오히려 좋아?'라는 생각이 든다.

 

결국 개발자 입장에서는 개발편의성과 유지보수성을 생각할 수 밖에 없기에 식별관계로 이루어진 복합키에 대해 잠자면서도 생각했던 것 같다.

위 사이트가 많은 생각을 하게 해주었다.

 

여러 도서에서는 모델링을 완벽하게 수행해야 개발 도중에 다시 갈아엎는 상황이 생기지 않는다고 한다.

그러나 시간이 부족하거나 지나면서 완벽한 모델링은 없다고 깨달을 것이다.

완벽한 모델링과 실제 개발간의 괴리는 불가피하며, 미래의 변경에 대비하는 것이 가장 중요하다는 것을 깨닫게 된다.

 

그렇다면 많은 개발자들이 비즈니스와 개발편의성, 유지보수성을 위해 시퀀스를 사용하는 것일까?

아니면 성능을 포기한 것일까?

이는 하드웨어 성능이 향상됨에 따라 식별관계를 통한 성능이 요구되지 않아도 충분한 퍼포먼스를 얻을 수 있다는 측면도 있는 것 같다.

 

결국 프로젝트 특성과 개발 상황을 고려하여 DB 모델을 유연하게 만드는 방법에 대한 고민은 충분한 시간이 필요하지만, 이렇지 않을 경우거나 DBA가 없다면, 이커머스처럼 MAU가 백만명 넘는 활발한 사용자가 없다면?

시퀀스를 사용하여 테이블 간에 비식별자 관계로 두고 빠른 개발을 하는 것이 낫다고 본다.