'PK를 업무와 관련된 키로 설정하는 것이 좋을까' 에 대한 고민
제목: 'PK를 업무와 관련된 키로 설정하는 것이 좋을까' 에 대한 고민
InnoDB 스토리지 엔진에서는 클러스터링 인덱스를 사용하기 때문에 PK(Primary Key)의 선택이 개발하는 서비스의 성능에 전반적으로 중요한 영향을 미친다. 일반적으로 AUTO_INCREMENT 컬럼을 사용해 별도의 surrogate key를 PK로 사용하는 경우가 많지만, 업무적으로 의미가 있는 컬럼을 PK로 설정하는 것이 더 효율적인 경우가 많다고 알려져 있다.
널리 알려져 있는 것과는 별개로, 어떤 경우에 우리가 업무 도메인에서 해당 키를 PK로 설정했을 때 이득을 볼 수 있는지는 또 별개의 문제라고 생각한다. 그래서 약간의 케이스들을 찾거나 고민해본 뒤 정리해보기로 하였다.
[업무 관련 PK를 사용하는 것이 좋은 경우]
자연키(Natural Key)가 적합한 상황
: 몇 번을 강조해도 모자라지만, InnoDB에서는 PK를 통해 물리적 위치가 결정되기 때문에 PK 검색 처리 속도가 굉장히 빠르다 (클러스터링 인덱스). 따라서 실제 업무에서 자주 사용되는 컬럼을 PK로 설정하면 검색 성능을 최적화할 수 있다.
키 유형 | 장점 | 단점 |
자연키 | - 의미 있는 데이터로 직관적 인식 가능 - 별도의 추가 컬럼 불필요 |
- 변동 가능성 존재 - 민감 정보일 가능성 |
인조키 | - 관리 용이 - 변동 가능성 없음 |
- 데이터 의미 파악 어려움 - 무의미한 증가 값 |
사례 1: 고객 식별자
- 주민등록번호, 사업자등록번호, 여권번호 등 고유하고 변경 가능성이 낮은 식별자.
- 옛날부터 논쟁거리가 된 사례이다. 실제로 일반적인 서비스에서는 더 이상 주민등록번호를 데이터베이스에 저장하는 것이 일반적으로 불가능해진 걸로 안다.
- 이러한 문제로 기존에 이를 PK로 사용하고 있던 서비스들이 여러 애로사항이 발생했던 것으로 알려져 있다. (2014년 8월 7일부터 개인정보보호법 제24조의2 신설)
- 이 케이스에 어떻게 안전하게 PK를 바꿀 수 있을지에 대한 고민도 해보면 재밌을 것 같다.
- 예를 들어, 주민등록번호를 PK로 사용하는 문제는 민감 정보이기 때문에 보안 사고 발생 시 매우 치명적이다. 특히, 개인정보보호법이 강화되면서 DB 스키마를 수정하지 않으면 데이터 유출 리스크를 피하기 어렵다. 과거에 주민등록번호를 PK로 사용하던 시스템들이 법 개정 이후 이를 수정하지 못해 대규모 리팩토링이 필요했던 사례도 있었다.
- 그렇다면 주민등록번호 같은 식별 값을 믿을 수 있을 것인가? 인조 식별자를 사용하는 게 나을까?
사례 2: 제품 코드 시스템
- 제품 코드가 체계적으로 관리되고 유일성이 보장되는 경우
- 예: ISBN(도서 식별 번호), 자동차 번호, 전자제품 시리얼 번호
- 제품 코드가 불변이거나 유일성을 보장할 수 있다면 이를 PK로 사용해도 좋다. 그러나 코드 체계가 바뀌거나 유일성이 깨질 가능성이 있다면 인조키를 사용하는 게 안전하다.
사례 3: 지역 기반 코드 시스템
- 우편번호, 행정구역 코드 등 지역을 식별하는 코드 체계가 잘 정립된 경우
- 물론 변경이 잘 일어나지 않으므로, 지역 기반 코드가 안정적이라면 PK로 사용하기에 적합하다. 하지만 지역 코드 체계가 바뀌거나 새로운 코드가 추가될 가능성도 염두에 둬야 한다.
[AUTO_INCREMENT 사용에 대한 고민]
자연키가 우리가 컨트롤이 가능한 영역이라면 PK로 사용하는 게 괜찮은 선택이라고 느껴지는 것 같다. 하지만 주민등록번호의 사례 같은 문제라면 AUTO_INCREMENT를 사용하는 편이 속이 편할 것이다.
AUTO_INCREMENT를 사용하는 경우, 데이터가 단일 서버에서 관리될 때는 문제가 없지만, 수평 확장(Sharding)이 필요한 대규모 시스템에서는 중복 키 문제를 유발할 수 있다. 또한, 삽입 속도 저하가 발생할 수 있으며, 트랜잭션 충돌 가능성도 높아진다. 이러한 이유로 일부 대규모 서비스에서는 UUID나 복합키를 사용하여 중복 문제를 방지한다.
실제로 클러스터링 인덱스의 큰 강점은 물리적으로 정렬이 되어있기 때문에 정렬된 범위 조회에 매우 큰 이점을 가지고 있다는 것인데, 이를 통해 얻을 수 있는 자연키는 그렇게 많을 것 같다고 생각이 들진 않는다. 따라서 나의 경우에는 대다수의 경우 AUTO_INCREMENT를 사용할 것 같다. (너무 뻔한 이야기가 된 것 같기도 하다.)
[마무리]
너무 뻔하다고 느꼈다면, 이 글을 통해 왜 이런 논의가 있었을까를 다시 고민해보면 좋을 것 같다. 클러스터링 인덱스에 대해서 말이다.
InnoDB에서 PK를 업무와 관련된 키로 설정하는 것은 상황에 따라 적절할 수도, 그렇지 않을 수도 있다. 정답이 없는 문제이지만, 데이터 접근 패턴과 업무 특성을 고려하여 최적의 설계를 선택하는 것이 중요하다. (갑자기 더 진부해진 것 같다.)