#title 상태이력 [[TableOfContents]] ==== 개요 ==== Fact에는 Measure만 있는 것이 아니다. 주문번호와 같은 DD(Degenerate Dimension)도 Fact Table에 존재할 수 있다. 상태이력도 마찬가지로 Fact Table에 존재할 수 있다. 하지만 상태이력과 같은 몇 가지의 코드성 데이터의 경우에는 꼭 Fact Table에만 넣을 수 있는 것이 아니다. 데이터의 양이 많은 경우는 차원으로 뺄 수도 있다. 하지만 데이터의 양을 줄여 성능을 높일 수 있을 대신에 차원이 복잡해지는 단점이 존재한다. 다음의 모델을 토대로 상태에 대한 이력이 팩트에 들어갈 것인지 차원에 들어갈지 생각해보자. 고객이 상품을 주기적으로 "자동"으로 구매에서 배송까지 고객이 설정한 기준으로 프로세스가 이루어진다고 가정해보자. 물론 구매시마다 "수동"으로 할 수도 있다는 시나리오다. attachment:상태이력/state01.jpg 위의 그림과 같에서 "상태"를 팩트에 저장하든지 차원에 저장하든지 각각 장/단점이 존재한다. 각각을 살펴보자. ==== 상태이력이 Fact에 있는 경우 ==== 상태이력이 Fact에 있는 경우의 모델은 다음과 같은 2가지 방법이 있다. attachment:상태이력/state02.jpg A모델의 "자동여부"의 경우를 앞서 이야기 했던 DD(Degenerated Dimension, 퇴화된 차원)이라고 한다. 말 그대로 퇴화된 차원으로 물리적인 테이블로 묶기도 애매하고, 차원으로 보기에도 애매한 차원을 말한다. A모델의 가장 큰 장점은 단순성이다. 물론 자동/수동이 숫자 1, 0과 같이 저장될 수도 있고, 문자로 '자동', '수동'으로 저장될 수도 있다. 숫자형으로 저장될 경우는 1이 '자동'을 의미하는지 '수동'을 의미하는지 시스템이나 문서 어딘가에는 명시되고 지켜야하는 규칙이 된다. 초기에는 1,0과 같이 2가지의 값을 가져야 하지만 규칙이 타이트하지 않다면 또 다른 숫자가 입력 될 수도 있다. 그러므로 문서나 규칙에 대한 지속적인 유지보수(변경관리)도 필요하다. 문자로 '자동', '수동'으로 Fact에 저장될 경우의 가장 큰 단점은 Fact의 크기에 영향을 미친다는 것이다. 4Byte 정도이지만 Fact의 Row당 1Byte는 매우 중요하다. 성능 문제도 일조한다. 또한 문자열이므로 숫자형일 경우보다 훨씬 더 많은 종류의 데이터가 들어갈 수 있다. 그러므로 규칙에 신경써야 한다. B모델의 경우는 DD가 팩트에서 차원으로 빠져 나왔다. 물리적으로 구현되면 아마도 아래와 같은 뷰로 만들어지거나 실제 물리적인 테이블의 형태가 될 것이다. {{{ SELECT 0 자동여부키, '자동' 자동여부 UNION ALL SELECT 1 자동여부키, '수동' 자동여부 }}} B모델의 경우 차원이라고 만들어지기는 했지만 사실 Surrogate Key를 제외하면 본래의 속성은 1개이므로 엔터티의 자격이 없다. 그렇다고 차원이라고 하기에도 빈약하다. 하지만 모델은 매우 명확하다. 스타스키마를 조금만 알아도 '아 이것은 차원이구나'라고 알 수 있다. 또한 '자동', '수동'과 같은 문자열이 Fact로 입력되지 않아도 되어 Fact의 크기를 줄였고, 코드화되었다는 것도 장점이 된다. 하지만 차원이 하나 더 늘어났으므로 모델 자체는 복잡해졌다. ==== 상태이력이 Dimension에 있는 경우 ==== 모델을 이렇게 만든다고 한다면 어떤 차원에 '자동여부'를 넣을 것인지 잘 생각해야 한다. 왜냐하면 차원의 개념이 희석되어 넓어지게 되고, 차원의 Row수도 최소 2배이상 늘어나기 때문이다. 예를 들어, 다음과 같이 고객 * 자동여부 만큼 Row수가 늘어난다. 또한 도메인도 고객 + 자동여부가 된다. 아무리 DW는 비정규화라지만 지나친 것은 반드시 화를 부른다. ||고객Key||고객ID||자동여부|| ||1||yasicom||자동|| ||2||yasicom||수동|| ||3||lee||자동|| ||4||lee||수동|| ||5||kim||자동|| ||...||...||...|| 위 모델에서 날짜나 고객은 공용으로 쓰이는 차원이므로 변경의 영향이 매우 크다. 고객과 같은 차원은 Row수가 매우 많은 대형차원이므로 이를 뻥튀기 한다면 매우 큰 부담이 된다. 날짜의 경우는 대부분의 Fact에서 쓰는 것으로 개념의 범위가 좁은 것이 좋다. 하지만 상품과 같은 것은 아마도 '매출' 주제영역에만 영향을 끼칠 것이다. 그러므로 상품차원에 '자동여부'를 두기로 하는 것이 좋을 것이다. 다음은 '자동여부'를 상품에 둔 경우이다. ||상품키||상품명||자동여부|| ||1||사탕||자동|| ||2||사탕||수동|| ||3||과자||자동|| ||4||과자||수동|| ||5||초콜릿||자동|| ||6||초콜릿||수동|| ||...||...||...|| attachment:상태이력/state04.jpg 주의해야 할 것은 상품명이 기존에 Unique했더라도 '자동여부'를 포함함에 따라서 더 이상 Unique하지 않게 되었다는 것이다. 또한 '자동여부'를 알기 위해서는 꼭 상품차원을 들춰봐야 알 수 있다는 것이다. 역시 상품도 더 이상 우리가 알고 있던 그 '상품'이 아니라 '상품 + 자동여부'를 의미하게 되므로 차원의 도메인이 넓어진다. 도메인이 넓어진다는 것은 마치 상품이 '상품 비스무리한 것'이 되는 것과 같다. 애매모호해 진다는 것이다. 그럼에도 불구하고 이런 모델이 존재할 수 있는 이유는 '성능' 상의 이유다. Fact에 '자동여부'가 없으므로 성능상의 여러가지 이득이 있다. 기본적으로 Fact의 크기가 작아지므로 처리량이 줄어들 것이고, 부수적으로 최소 입/출력 단위에 꽉꽉 채울 수 있으므로 더 적은 I/O로 요청을 처리할 수 있다. ==== 결론 ==== '상태이력'과 같이 적은 경우의 수를 가지는 컬럼을 가지고 여러가지 장/단점을 살펴보았다. 상태이력이 Fact에 있는 경우의 모델(1)은 구현하기 쉽고, 모델 자체가 단순하다. 또한 선택의 여지가 있다. 상태이력이 Dimension에 있는 경우(2)는 성능상의 이점이 있다. 하지만 (2)의 경우는 성능상의 장점을 빼고는 도대체 장점을 찾아 볼 수가 없고, 잃는 것도 많다. 성능상의 문제가 적시성의 결여로 이어지는 경우가 아니라면 (1)과 같은 모델을 선택하는 것이 옳은 결정이 될 것이다.