복합키 사용 이유 - boghabki sayong iyu

오늘은 여러개의 속성이 모여서 식별자를 구성하고 있는 경우를 살펴보겠습니다. 

사족인데요,

음 이 말을 다시하면 여러개의 컬럼이 모여서 Primary Key를 구성하고 있는 경우를 살펴보자는 말이죠. 논리 모델과 물리 모델에서 사용하는 용어차이가 있다는 얘긴데요. 개인적으론 조금 고민입니다. 대체로 Database와 통용되는 물리모델의 용어에 더 익숙하실거라 그 용어를 사용해서 설명하고 대화하긴 하지만, 분석하는 입장에서 모델을 말하자면 사실 논리 모델 용어가 더 의미상 정확한 경우가 많든요. 

흠.. 이래저래 저는 지금까지 섞어써왔을것 같네요. 이해를 위한 최선의 선택이었다는 변명을...;-)

예를들어 어느 보험회사의 보험계약내역 이라는 테이블의 키가 다음과 같이 구성되어 있다고 하겠습니다.

복합키 사용 이유 - boghabki sayong iyu

그림1. 보험계약내역 

총 다섯개의 컬럼이네요. 키 속성이 많아지면 분석하는 입장에서는 눈에 거슬리기 시작합니다.

일단 컬럼숫자가 너무 많거든요. 

보험계약내역 테이블 자체 보다도 이것과 관계가 있는 다른 테이블들이 그렇습니다.

예를들어 보험계약 번호가 바뀌는 경우 이 전후 컬럼을 관리하면 이렇게 됩니다. 

그림2. 보험계약내역 + 보험계약내역번호변경내역

복합키를 가진 테이블이 중요한 핵심 테이블일 경우 이러한 현상이 일파만파로 퍼져나가게 됩니다. 지금 예로든 보험계약 내역도 핵심 테이블인 경우구요.

그리고, 데이터를 조회하기 위한 SQL 문이 복잡해집니다. 보험계약내역과 다른 테이블을 join 하고자 할때, where 절에 5개의 조건이 기술되어야 할 경우가 매우 많을 테니까요.

그럼 어떻게 하는게 좋을까요? 

이럴때 생각할 수 있는것이 키를 인공적으로 만드는 것입니다. 위에 보셨던 다섯개 컬럼의 키는 업무가 그대로 드러나 있기 때문에 업무키 (Business Key) 라고 하구요, 이에 비해 앞으로 설명할 키를 인조키(Artificial Key)라고 합니다. 

음.. 인조키를 만드는 데는 대표적으로 두가지 방법을 생각해 볼 수 있습니다. 

하나는 비즈니스키를 이어붙여서 (concatenate) 하나의 컬럼으로 만들어 사용하는 것이구요,

만약 원래 컬럼들의 길이가 다음과 같다면요.

지점코드(4) + 팀코드(3) + 보험유형구분(1) + 계약연도(4) + 일련번호(4)

인조키의 킬이는 이렇게 되겠지요

보험계약내역식별번호(16)

다른 하나는 아예 시퀀스와 같은 충분히 긴 길이의 일련번호를 만들어 사용하는 겁니다. 

보험계약내역식별번호(10)

실제 데이터 예제는 이렇겠네요.

- 복합키  : "AAA" + "T10" + "3" + "2013" + "0130"

- 인조키1 : "AAAT10320130130"

- 인조키2 : "0000000240"

이제 하나의 컬럼이 키가되어 모델이 깔끔해 졌습니다. 보험계약내역 테이블 자체도 그 키를 Foreign Key로 가지고 있는 다른 테이블 들도 그렇지요. SQL 문을 작성해도 조건절 한줄로 join을 걸 수 있게 됐네요.

그럼 이제 모두 해피? ;)

그렇진 않습니다. 모든일에는 장단점이 있는데요. 인조키의 대표적 한계점 개별적 컬럼들이 의미 있는 조건인 경우가 많아 완전히 없애긴 어렵다는 것입니다. 

예제에서는 지점코드나 보험 유형이 조회를 위한 조건으로 빈번하게 사용된다는 점을 생각해 보면 이해하실 수 있을거에요. 보험유형을 조회 조건으로 사용하려면 하나의 컬럼으로 묶어버린 인조키에서는, substr 과 같은 함수를 사용해서 보험유형 부분을 잘라내서 비교해야 하구요. 이렇게 조건절에 키 컬럼에 대해 함수를 사용한 조건을 걸면 인덱스를 사용하지 않기 때문에 검색속도가 상당히 떨어집니다.

어쩔수없이 조회조건으로 많이 사용되는 컬럼은 추가로 가지고 있어야 합니다. 모든 내용이 조합된 인조키에 일부로 포함되어 있더라도 말이죠. 

그림3. 조회조건용 컬럼중복 설계

오늘은 복합키를 가진 테이블의 키를 재설계하는 방법을 살펴봤습니다. 도움이 되셨으면 좋겠네요. 

해당 컨텐츠는 주간동안 읽은 아티클 중 일부를 정리한 내용입니다.

주저리

시퀀스 PK와 복합키 PK에 대하여

요즘 복합키를 PK로 잡는 경우를 종종 접하는데, 오라클 + C 베이스의 금융쪽 개발자들이 자주 사용하는 방식으로 보인다. 필자는 5월에 이직하면서 접하게 되었는데, 이전까지는 Auto Increment를 주로 PK로 사용했기때문에 복합키 PK에 대해 매우 낯설었다.

뿐만 아니라 이전 회사까지는 Mysql을 사용해왔는데 Mysql에서는 복합키를 PK로 두면 성능적이슈가 있다. Mysql은 pk를 클러스티드 인덱스로 관리하기 때문에 항상 정렬된 상태를 유지해야하면 인덱스 테이블들이 모두 이 PK를 물고있어 단일필드로 보통 PK를 설정한다.

Mysql에서는 복합키 PK는 좋은 선택이 아님은 분명하다. 그렇다면 위와 같은 제약이 없는 DB들에서 복합키가 가지는 장단점을 알아보자.

우선 실제 데이터들로 구성된 복합키를 잡는 과정에는 해당 필드들에 변경이 없을거라는 강한 가정이 있어야한다. 이러한 가정이 깨지는 경우, 후 처리가 상당히 피곤해진다. 다만 이 가정이 있기때문에 테이블의 생성규칙과 서로의 연관관계를 파악할 수 있다.

또한 다른 테이블과 연관관계 역시 복합키로 맺기 때문에 조인의 횟수나 쿼리처리가 단순해지는 부분이 있다. 복합키에 데이터로만 처리가 가능하다면 굳이 조인을 할 필요가 없어지고, where 절등에 대한 처리 역시 훨씬 단순해진다. 시퀀스 Pk에서도 중복을 허용하고 같은 방법의 최적화가 가능한데, Pk가 아니기때문에 변경의 여지가 있으므로, 중복데이터들 관리에 신경써야한다.

그렇다면 복합키 PK가 더 좋은 선택인가? 그렇지만은 않다. 특히 JPA를 쓴다면 복합키 PK를 관리하기 위한 많은 수고가 필요하다. 단적인 예로 컨텍스트의 캐시 키 사이즈가 증가한다. 사실 이번 주제에서 가장 하고 싶었던 애기는 시퀀스 PK든 복합키 PK든 서로의 장단이 분명히 존재하고 무조건적으로 좋고 나쁜 것은 없다이다.

Article

In Java, what is the best way to determine the size of an object?

업무를 진행하면서, 메모리 사이즈 측정에 대한 니즈가 있었다. 많은 방법들이 위 아티클에 소개되어 있는데 필자가 생각하기에 가장 간단한 방법은 인텔리제이의 메모리 에이전트를 사용하는 것이다. 해당 아티클을 통해 이 기능을 알게되었고 공식 홈페이지에 사용방법이 잘 설명되어 있다.

Book

데이터 중심 애플리케이션 설계 - 10장 일괄배치

10장은 대용량 일괄배치로 주로 하둡 맵리듀스에 대한 애기를 다루고 있다. 10장 초반에 유닉스의 철학을 간략하게 소개하는데 이 철학이 대규모 이기종 분산시스템에서도 크게 다르지 않다고 애기하고 있다. 내용은 아래와 같다.

1. 각 프로그램이 한가지 일만 하도록 작성하다.
2. 모든 프로그램의 출력이 아직 알려지지 않은 다른 프로그램의 입력으로 쓰일 수 있다고 생각하라.
3. 소프트웨어를 빠르게 써볼 수 있게 설계하고 구축하라. 거슬리는 부분은 과감히 버리고 새로 구축하라.
4. 작업을 줄이려면 미숙한 도움보단 도구를 사용하라.

특히 유닉스는 파일 디스크립터를 통해 2번을 구현했다. 유닉스에서 파일은 표준 입출력, 소켓, 실제 파일 등과 같이 여러가지 것을 표현할 수 있고 이질적인 것들이 하나의 인터페이스를 공유하고 있다는 점이 인상 깊었다.

이후 맵리듀스에 대한 간략한 내용들이 소개하고 있다. 필자는 백엔드 엔지니어라 크게 와닿지는 않았지만 인상 깊었던 내용을 간략하게 정리하면 아래와 같다.

- 맵리듀스 작업은 인덱스가 없다. 대량의 레코드 대상의 집계연산이 일반적이기에 이는 상당히 합리적이다.
- 입력이 불변이고, 실패한 테스크의 출력을 폐기하기때문에 재시도는 안전하다.
- 이상적인 데이터 모델을 만들려고 하기보다 데이터를 빨리 사용 가능하게 만드는 것이 더 가치있다. 그러므로 데이터 셋을 강제하는 대신 데이터 해석을 소비자에게 맡겨라(스키마 온 리드)
- 결함으로부터 신뢰성 있게 회복하기 위해서는 비결정적 원인을 제거해야한다.
- 연산의 재시도의 중요한 점은 연산이 결정적인지 아닌지 판단하는 것이다.

도메인 주도 설계 - 17장 전략의 종합

1장 ~ 16장은 17장을 이해하기 위한 준비단계 같았다. 필자가 느끼기에 이 책의 핵심은 17장이라 생각한다. 17장은 기술적 또는 개념적 내용을 설명하기보다, 앞에서 배운 개념들을 어떻게 적용하고 전략적 설계와 이에 적합한 팀의 구조, 일하는 방식에 대해 설명있어 시니어가 되었을 때 다시 읽어봐도 좋을 거 같다.

좋은 소프트웨어를 만들어 내는 것은 학습과 사고 활동이라는 핵심적인 사실을 간과해서는 안된다.