아래의 글은 모델러에 따라 생각이 다를 수 있음을 밝혀둔다. 모델링에는 정답이 없다. 하지만 모범답안을 찾기 위해 노력해야 한다.

역정규화는 정합성과 확장성을 방해한다.
많은 종류의 모델링 책에 위와 같은 이유로 물리모델링단계에서 역정규화를 해야 한다고 되어 있다. 즉 정합성과 확장성이 나빠짐으로 논리모델링시에는 정규화를 하고 물리모델링 시에는 역정규화를 해야 한다는 것이다. 하지만 과연 그럴까? 몇몇의 경우는 물리모델링에서 역정규화를 적용하는 것이 옳을 수도 있다. 하지만 항상 그런 것은 아니다. 오늘은 역정규화에 잘못된 관행에 대하여 알아보도록 하자
.

역정규화를 해야 하는 이유는 두 가지이다.

첫 번째, 성능관점이다. 대표적인 것이 항상 조인이 발생함으로 조인에 의한 성능저하를 막아보자는 것이다. 또 다른 예제는 목적성(집계) 테이블이다. Source 테이블을 직접 Group By + SUM 을 한다면 SQL의 성능이 느려지는 것은 불을 보듯 뻔한 것이다. 목적성 테이블에는 상태를 나타내는 테이블도 있다. 대표적인 것이 상품의 현재고 테이블이다.

두 번째, 개발 생산성 관점이다. 대표적인 예제는 고객테이블의 고객전화번호이다. 예를 들면 자택전화번호, 직장본사전화번호, 직장 파견지 전화번호, 핸드폰번호, 기타전화번호로 전화번호가 여러 개인경우에 고객연락처를 별도로 분리하여 정규화를 하게 된다. 이럴 때 PK 는 고객번호 + 연락처구분코드 가 되며 테이블의 확장성이 좋아진다. 하지만 모든 조회 화면에서 고객의 전화번호를 가로로 나열한다면? 성능은 물론이고 개발자의 생산성 또한 좋지 못할 것이다.


위의 두 가지 관점을 모두 가지고 있는 경우가 있다. 대표적인 것이 재고 테이블이다. 재고테이블은 성능의 관점과 개발생산성의 관점을 모두 고려한 것이다. 제조나 유통 프로젝트의 경우 재고 테이블이 없다면 개발하는데 엄청난 공수를 들여야 할 것이다. 이론적으로 상품의 현재고는 다음과 같이 구할 수 있다.

현재고 = 전월 이월수량 + 이번 달 입고수량 - 이번 달 출고수량 - 출고 되지 않은 주문 수량 + 재고로 사용할 수 있는 이번 달 반품수량 + 기타


논리모델링에서 역정규화를 해야 되는 경우
논리 모델링 단계에서 재고엔티티가 없어도 위의 식을 사용한다면 논리적으로 문제될 것이 없다. 하지만 업무의 핵심인 입고, 출고, 반품, 주문 등에 의하여 지속적으로 영향을 받는 업무적으로도 중요한 테이블이 된다. 또한 재고실사(실제로 재고가 몇 개인지 검증)를 하게 되면 재고테이블의 수량에 직접 영향을 끼친다. 이러한 여러 가지 이유로 재고 테이블은 논리모델링에서 나오는 것이 좋다. 이유는 성능이나 개발생산성 관점뿐만 아니라 업무적인 관점과 집합의 중요성을 감안 해야하며 중요한 엔티티가 없을 경우 Communication 이 어려워지기 때문이다. 심지어 개념모델링에서도 재고를 엔티티로 나타내는 모델러도 있다.

Table Generation
이후에 역정규화를 해야 하는 경우

성능상의 문제로 역정규화를 고려하는 경우이다. 필자가 역정규화를 적용한 대부분의 경우가 여기에 해당한다. 예를 들어 고객테이블의 고객명을 역정규화 해야 한다고 생각해 보자. 물리모델링단계 이후에 Table Generation 이 끝나고 데이터 이관작업이 끝나고 인덱스 디자인 작업이 끝나야 SQL 의 성능이 느린지 아닌지 알 수 있다.

나는 질문한다
나는 물리모델링단계에서 모든 역정규화를 적용했다는 사람에게 묻고 싶다.  도대체 무엇을 보고 물리모델링 단계에서 SQL이 느린지 알 수 있단 말인가?  물리 모델링 단계에서는 SQL을 알 수 없는 것은 물론이고 물리적인 테이블이나 인덱스가 없다. SQL을 실행시킬수도 없는 환경에서 모든 역정규화를 적용했단 말인가? 책에 나와 있다고 혹은 고참이 그렇게 한다고 혹은 경험이나 감으로 역정규화를 적용 했는가? 이런 일이 반복되어서는 안된다.


구체적인 예를 들어보자

성능목표를 모든 조회화면의 90% 2.5초 이내에 수행되어야 한다. 라고 정의 했다면 해당 SQL 2.5 초가 걸리는지 안 걸리는 지는 데이터가 이행이 되고 쓸만한 인덱스가 설계된 이후에나 알수 있다.

뻔한 것은 물리모델링 시에 역정규화 할 수 있다

대표적인 것이 고객테이블의 고객전화번호이다. 예를 들면 자택전화번호, 직장 본사 전화번호, 직장 파견지 전화번호, 핸드폰번호로 전화번호가 여러 개인경우에 고객연락처를 별도로 분리하여 논리 모델링시에 정규화를 하게 된다. 이럴 때 PK 는 고객번호 + 연락처구분코드 가 되며 테이블의 확장성이 좋아진다.

하지만 물리모델링 시에 화면 설계서를 볼 수 있고 거의 모든 조회 화면에서 고객의 전화번호를 가로로 나열한다면? 이때는 물리모델링 시에 역정규화를 하는 것이 옳다. 개발생산성과 성능의 향상은 불을 보듯 뻔한 것이므로 하지만 이 경우에도 전화번호의 종류가 계속하여 늘어난다면 역정규화를 적용하는 것은 다시 생각해보아야 한다
.

일부의 집계테이블도 물리모델링 단계에서 역정규화가 가능하다

화면 정의서에서 원본 테이블을 지속적으로 Group By + Sum 하는 형태라면 물리모델링시에 집계테이블을 생성 할 수 있다. 하지만 이런 경우라 할지라도 화면에 해당하는 SQL   성능 목표인 2.5초가 넘는지 정확히 알 수 없다. 인덱스 나 파티션, 클러스터링 팩터에 의하여 달라진다. 또한 화면의 조회조건이 어떻게 되느냐에 따라 SQL의 성능은 달라진다. 어느 프로젝트의 경우 성능목표보다 6배 이상 빠른 경우에도 역정규화를 적용하여 데이터의 정합성에 문제가 된 적이 있다.

역정규화는 최소화 되어야 해
개발생산성과 성능이란 두 가지 관점에서 역정규화는 필요하다. 하지만 역정규화는 정합성과 확장성을 해치기 때문에 최소화 되어야 한다. 모델러의 경험이나 감으로 역정규화를 하는 경우가 많다. 그렇게 하면 필요치 않은 역정규화가 발생할 수 있다. 모델링의 각 단계(논리모델링/물리모델링/Generation 이후)에서 해야 할 것과 하지 말아야 할 것을 잘 따져서 해야 한다.

성능관점의 역정규화는 데이터 이행 이후에 고려하라

특히 성능관점에서는 Table Generation 이후 + 인덱스 디자인 이후 + 데이터 이행 이후에 목표성능을 만족하지 않는 경우에만 적용하는 것이 역정규화를 최소화 한다는 관점에서 가장 바람 직 하다. 필자가 이런 글을 쓰는 이유는 역정규화는 무조건 물리모델링단계에서 하는 것 으로 생각하는 모델러가 대부분이기 때문이다.

결론:

바둑을 잘 두려면 정석은 모두 알아야 한다. 하지만 정석을 알고 난 이후에 프로기사가 되려면 정석을 까먹어야 한다. 틀에 박하지 않은 새로운 정석을 만들어야 하기 때문이고 실제로 프로기사들은 새로운 정석을 계속 만들어 낸다. 역정규화는 무조건 물리모델링단계에서 하는 것 이란 말이 아주 잘못된 말은 아니다. 하지만 개념을 알았다면 까먹어라. 더 좋은 새로운 정석을 만들기 위해서  

PS
1.
현실적으로 모델링의 기간이 매우 짧으므로 물리모델링단계에서 모든 것을 해야 하는 경우도 있다. 하지만 이런 경우를 원칙으로 가이드를 하거나 책을 쓰는 것은 옳지 않다
.
2.
프로젝트 에서 물리모델링 기간을 시스템 Open 직전까지 가져가는 경우가 있다. 이런 경우는 물리모델링단계에서 역정규화를 하는 것이 옳다. 하지만 이때에도 뻔한 경우가 아니라면 데이터 이행 이후에 쓸만한 인덱스가 있어도 성능이 나오지 않는 경우에  역정규화를 고려하는 것이 가장 정확하다.


Posted by extremedb
,