DB/SQL 전문가 가이드

[과목 I 2장 5절] 본질식별자 vs. 인조식별자

꾸준함. 2025. 3. 17. 23:22

본질식별자 vs 인조식별자

  • 엔티티는 반드시 데이터를 식별할 수 있는 속성이 존재해야 하며 이를 식별자라고 지칭
  • 식별자는 대체 여부에 따라 본질식별자와 인조식별자로 분류 가능
    • 본질식별자: 업무에 의해 만들어진 식별자
    • 인조식별자: 업무적으로 만들어지지는 않지만 본질식별자가 복잡한 구성을 갖고 있으므로 인위적으로 만든 식별자

 

가. 본질 식별자

 

https://highllight.tistory.com/77

 

  • [그림 I-2-21] 주문상품 모델의 식별자가 본질식별자
    • 주문상품 모델은 주문 시 구매한 상품 정보를 관리

 

  • 아래 표는 하나의 주문에 세 개의 상품을 구매한 것을 데이터로 표현했으며 이러한 데이터로 개발을 진행하여 주문상품 모델에 값을 Insert 하는 경우 다음과 같이 SQL로 표현 가능

 

 

주문번호 상품번호 주문수량
110001 1234 1
110001 1566 5
110001 234 2

 

나. 인조 식별자의 나쁜 예

 

https://highllight.tistory.com/77

 

  • [그림 I-2-22] 모델은 주문상품번호라는 새로운 식별자를 생성하였고 해당 식별자를 외부식별자라고 지칭
  • 해당 모델의 Insert문은 다음과 같음
    • 해당 SQL문은 `주문상품번호SEQ`라는 시퀀스 객체를 생성하고 NEXTVAL 기능을 이용하여 자동으로 값을 채번하여 Insert 하는 방식
    • 오히려 불필요한 시퀀스를 생성하기 때문에 앞서 본질식별자에 비해 이점이 없어 보임

 

 

  • 별다른 이점이 없어 보임에도 위와 같이 모델을 생성하는 가장 큰 이유는 본질식별자에 대해 고민하지 않았기 때문
    • 대체로 모델에 대한 이해도가 높지 않은 상태에서 모델을 설계하다 보면, 식별자는 유일성과 존재성 (Unique, Not Null)만 만족하면 된다고 생각할 수 있기 때문
    • DBMS에서 기본 키를 생성하면 Unique와 Not Null 제약이 생기므로 데이터 입력 시 오류가 발생함
    • 즉 데이터 입력 시 에러가 발생하는 것에 대해서만 고려하고, 실제 해당 엔티티의 본질식별자에 대한 고민을 하지 않았기 때문에 [그림 I-2-22]와 같은 모델이 만들어짐

 

다. 인조식별자를 사용했지만 애매한 예

 

https://highllight.tistory.com/77

 

  • 하나의 주문에 동일 상품을 중복 구매하고 싶을 때 [그림 I-2-21] 모델에서는 상품번호가 중복되기 때문에 불가능할 것
  • [그림 I-2-23]의 주문상세 모델은 상품번호를 식별자로 구성하지 않고 하나의 주문에 발생하는 상품의 Count를 주문순번이라는 속성으로 식별자를 구성

 

주문번호 주문순번 상품번호 상품명 배송지
110001 1 1234 제주감귤 1box 우리집
110001 2 1234 제주감귤 1box 부모님집
110001 3 1234 제주감귤 1box 친구집

 

 

  • 위 표를 보면, 동일 상품을 하나의 주문에서 처리하고 있음
    • 즉 쇼핑몰에서 동일한 상품 몇 개를 각기 다른 배송지에 보내고 싶은 요건을 나타낸 것
    • 만약 [그림 I-2-21]의 주문상품 모델이라면 위와 같은 요건을 처리하기 위해서 주문을 별도로 세 번 해야 할 것
    • 반면, [그림 I-2-23] 모델로 개발할 경우 다음과 같이 SQL이 호출될 것
      • 이전 모델과 다른 점은 주문순번 값을 위해 하나의 주문에 구매하는 상품의 Count를 계산하여 입력한다는 것
      • 이와 같은 작업은 어려운 일은 아니더라도 번거로운 작업이 추가된 것은 분명한 사실

 

 

라. 인조식별자를 적절히 사용한 예

 

https://highllight.tistory.com/77

 

  • [그림 I-2-24] 주문상세 모델은 식별자를 주문상세번호로 정의
    • 이전 모델과 차이점은 식별자를 하나의 속성으로 구성한 외부식별자로 생성
    • 주문순번 속성이 사라졌지만 대신 주문상세번호가 생성되었으므로 언뜻 보면 큰 차이 없어 보이지만 실제 개발 시 편의성이 향상되는 방식

 

주문상세번호 주문번호 상품번호 상품명 배송지
1 110001 1234 제주감귤 1box 우리집
2 110001 1234 제주감귤 1box 부모님집
3 110001 1234 제주감귤 1box 친구집

 

  • 앞서 `다 사례`의 표와 비교했을 때 주문순번이 주문상세번호로 바뀐 것 말고는 다른 점이 없어 보이지만 실제 해당 값을 구하는 방식을 비교해 보면 차이점을 알 수 있음
    • 주문순번은 하나의 주문번호에 대해 구매가 일어나는 상품의 Count를 구하는 것이므로 시퀀스 객체를 활용할 수 없어 별도로 작업을 해줘야 함
    • 반면, 주문상세번호는 단일식별자로 구성된 키 값이기 때문에 시퀀스 객체로 해결이 가능하므로 별도 작업이 필요 없음
    • 아래 SQL을 보면 더 명확하게 이해 가능


 

부연 설명

  • `주문상세번호SEQ`라는 시퀀스 객체를 만들고 NEXTVAL을 활용하면 기본 키에 대한 부분은 더 이상 신경 쓰지 않아도 되므로 실제 작업량이 줄어듦
  • 이처럼 인조 식별자를 적절히 사용하면 편하게 개발할 수 있지만 다음과 같은 문제점이 있음
    • 중복 데이터로 인한 품질
    • 불필요한 인덱스 생성

 

1. 중복 데이터로 인한 품질 문제

  • 외부식별자를 사용하면 중복 데이터를 막을 수 없음
    • 기본 키의 제약을 활용한다면 중복 데이터를 원천 차단할 수 있지만
    • 외부식별자는 기본 키를 인위적으로 생성한 속성으로 정의하였기 때문


 

  • 위 SQL의 두 번째 INSERT 문이 로직 오류로 인해 중복으로 발생되었다고 가정했을 때 중복된 데이터를 막을 수 없음
    • 기본 키를 인위적인 인조식별자로 구성하였으므로 기본 키 제약은 주문상세번호에 대해 적용되어 있기 때문
    • 위와 같은 상황이 발생헀을 때 실제 데이터는 아래와 같이 저장될 것

 

주문상세번호 주문번호 상품번호 상품명 배송지
1 110001 1234 제주감귤 1box 우리집
2 110001 1234 제주감귤 1box 우리집
3 110001 1234 제주감귤 1box 부모님집
4 110001 1234 제주감귤 1box 친구집

 

부연 설명

  • 주문 상세번호에 기본 키 제약이 적용되어 있고, 주문상세번호는 시퀀스를 사용하였기에 제약에 위배된 사항이 없기 때문에 두 번째 행 데이터가 중복으로 발생된 데이터임에도 저장된 것을 확인 가능
  • 만약 인조식별자가 아니라 `주문번호+주문순번`와 같이 본질식별자로 구성했다면 기본 키 제약조건에 의해 중복 저장을 방지할 수 있었을 것
    • 그러므로 최대한 본질식별자를 지향해야 하며 
    • 만약 외부식별자를 사용했다면, DBMS에서는 해당 경우를 막아줄 수 없기에 애플리케이션에서 이를 방지해줘야 함

 

2. 불필요한 인덱스 생성

본질식별자와 인조식별자를 사용했을 때 인덱스 구성에 대해 다음과 같은 차이점이 발생합니다.

 

https://highllight.tistory.com/77

 

  • 주문상품 모델 데이터에 접근한다고 가정했을 때 가장 기본적인 액세스 패턴은 다음 SQL과 같을 것
    • 가장 기본적이면서 일반적인 액세스 패턴
    • 이러한 SQL에 대해 본질식별자로 구성하면 PK 인덱스를 활용할 수 있겠지만, 인조식별자로 구성한다면 [그림 I-2-25]의 IX1과 같은 인덱스를 추가로 생성해주어야 할 것
    • 즉, 인조식별자를 사용한다면 불필요한 인덱스를 추가로 생성해야 하는 점을 명심해야 함
    • 또한 추가로 생성한 인덱스는 요량과 DML 성능에 영향을 줄 수 있음을 염두에 둬야 함


 

정리

  • 식별자의 속성이 너무 많아지는 경우 본질식별자와 인조식별자의 장단점을 따져보고 사용하자
  • 인조식별자의 남용을 피하고 꼭 필요한 경우에만 사용하는 것이 바람직함

 

참고

SQL 전문가 가이드 2020 개정판 - 한국데이터산업진흥원

반응형