#title 정규화와 물리적인 요소 [[TableOfContents]] * 이 문서에서는 정규화에 대한 구체적인 방법을 설명하지는 않는다. 정규화가 물리적으로 미치는 영향을 살펴볼 것이다. ==== 정규화란? ==== 데이터베이스를 다룬다면 “정규화”라는 말을 들어보았을 것이다. 정규화는 성능 튜닝의 도구이자 무결성을 지켜주는 데이터베이스 최고의 도구이다. 이 모든 것은 “데이터의 중복”을 없애는데 그 목적이 있다고 할 수 있겠다. (결점이 생기는 대부분의 원인도 데이터의 중복에 있다.) ==== 데이터의 중복 ==== 데이터의 중복을 없애는 것은 데이터베이스에서는 매우 중요한 일이다. 데이터의 중복은 통합된 정보의 취득을 어렵게 만든다. 또한 데이터베이스 시스템의 성능 저하의 원인이 되기도 한다. 물론 인덱스를 제대로 활용하지 못한다거나 H/W등의 병목 등의 여러 가지 상황적인 요소가 있을 수 있다. 그러나 이것은 충분히 쉽게 개선할 수 있다. 그러나 설계상의 문제로 데이터가 중복되는 것은 SQL이 복잡해지고, 성능 저하의 문제를 가져온다. 왜 그럴까? 이쯤에서 우리는 기본적인 컴퓨터의 구조를 생각해야 한다. 기초 전산학에는 “폰 노이만” 의 “프로그램 내장방식” 이라는 말이 나온다. 기본적으로 CPU는 Main Memory(RAM)에만 접근할 수 있다는 것이다. 그러므로 CPU가 처리하기 위해서는 데이터를 HDD에서 RAM으로 끌어 올려야만 한다. 이 비용은 컴퓨터에서는 매우 큰 비용이다. HDD가 매우 느린 하드웨어 자원이기 때문이다. 그렇다면 데이터의 중복이 있다고 생각을 해보자. HDD에서 RAM으로 데이터를 올려야 한다. 그러나 데이터가 중복되어 있다면 중복된 만큼 HDD는 읽기를 수행해야 하며, 저장공간도 더 필요한 것은 당연하다. 또한 RAM의 크기도 상대적으로 많이 필요하게 된다. 또한 CPU는 데이터가 중복된 만큼 더 처리를 해야 하는 것이다. 데이터의 중복으로 인해 이러한 결과는 성능 저하를 가져온다. 이것은 결국 정보의 질을 떨어뜨리는 일이고, 궁극적으로는 사용자의 정보 욕구를 만족시키지 못하는 결과를 초래하는 것이다. ==== 이상과 현실 ==== 데이터베이스에서 논리적으로 생각한다는 것은 물리적인 요소를 고려를 하지 않는다는 것이다. (물론 “논리” 라는 것의 개념의 범위가 이 문서에서는 이와 같다는 것이다.) 다음의 두 쿼리문이 있다. TAB이라는 테이블은 1천 만 건이다. ID 컬럼에는 1 ~ 10000000 까지의 번호가 순서대로 붙어 있다. ID 컬럼에 대하여 인덱스가 생성되어 있다. 물론 ID 컬럼 이외에 다른 여러 컬럼들이 있다. {{{ --1번 쿼리 SELECT * FROM TAB WHERE ID BETWEEN 1 AND 1000 --2번 쿼리 SELECT * FROM TAB WHERE ID BETWEEN 1001 AND 5000 }}} 대부분의 사람은 당연히 1번이 빠를 것이라고 대답할 것이다. 그러나 이것은 물리적은 상황을 고려하지 않은 상태의 얘기이다. 최악의 경우에는 응답시간이 1번보다 2번이 훨씬 빠를 수도 있다. 다음의 그림을 보자. attachment:design_tuning01.JPG 1 ~ 5000 은 1개의 페이지에 들어가 있고, 1, 2, 3 … 1000 은 각각의 페이지에 저장되어 있다면 1000개의 페이지에 접근해야 원하는 결과를 얻을 수 있다는 것이다. 위와 같은 물리적은 상황이라면 1001 ~ 5000의 로우는 MSSQL SERVER 2000의 경우 8KB만 읽으면 되고, 1 ~ 1000개의 로우는 모두 8KB * 1000인 약 8MB를 읽어야 처리를 할 수 있다는 것이다. 이 경우 데이터의 양이 작으므로 응답시간의 차는 눈에 띄게 차이가 나지 않을 것이다. 그러나 이러한 상황을 더 많은 데이터를 가지고 있는 테이블에 적용시킨다면 문제는 커진다. 위와 같이 “이상과 현실”이 존재한다. 이상적으로는 데이터 행이 조각화되어 있지 않고, 각각의 페이지에 꽉꽉 채워져 있다면 당연히 거의 이상적으로 처리할 수 있을 것이다. 아래의 예를 보자. TEST_NAME 컬럼이 CHAR(5000)이므로 당연히 MSSQL SERVER 2000에서는 1개의 페이지에 1개의 행만 삽입될 수 있다. 결과를 보면 알겠지만 페이지당 3083바이트가 낭비되고 있으며, 1만 행에 접근하기 위해서는 1만개의 페이지에 접근해야 한다. 엄청난 비효율이다. 이런 경우라면 당연히 CHAR대신에 VARCHAR을 써야 한다. (예에서는 입력되는 컬럼이 가변길이이다.) attachment:design_tuning02.JPG ==== 정규화와 물리적인 요소 ==== 비정규화 테이블은 일반적으로 컬럼의 개수가 많다. 컬럼의 개수가 많다는 이야기는 하나의 데이터 행의 크기가 크다는 의미이다. 위에서 살펴본 바와 같이 하나의 데이터 행의 크기가 크다면 당연히 최소 입출력 단위에는 데이터 행이 많이 들어가지 못한다. 최악의 경우 입출력은 매우 많이 읽어나고, 데이터 행이 각각의 페이지에 존재할 수 있다. 다음과 같이 테이블이 만들었다고 가정하자. {{{ CREATE TABLE 차량관리비내역( 차량번호 VARCHAR(10) , 관리부서 NUMBER , 연료 NUMBER , 주차비 NUMBER , 세차비 NUMBER , 윤활유 NUMBER , 부품대 NUMBER , 수리비 NUMBER , 타이어교환비 NUMBER , 자동차세 NUMBER , 환경세 NUMBER , 보험료 NUMBER ) }}} 잘 보면 이와 같은 경우는 명백한 1차 정규화 위배이다. 연료, 주차비, 세차비, 윤활유 등은 “차량관리비” 정도로 만들고, “구분” 컬럼을 만들면 된다. 즉, “차량관리비”는 다중값 속성이되어 다른 테이블로 떨어져 나가게 된다. 그래서 다음과 같은 논리 ERD가 그려질 것이다. attachment:design_tuning03.JPG?width=50% 각각의 테이블에 할당 받은 저장 공간을 효율적으로 사용하기 위해서는 테이블이 좁게 설계되어야 한다. 즉, 데이터 행을 하나의 최소 입출력 단위에 꽉꽉 채울 수 있다는 것이다. 뿐만 아니라 여러 가지 이상현상도 막을 수 있다. 예를 들어 “검사비”가 추가된다고 가정하자. 당연히 옆으로 컬럼이 나열되어 있는 경우는 테이블의 변경을 가져온다. 그러나 위와 같은 경우 비용과 구분만 넣어주면 그대로 끝난다. 최소한의 변경만으로 유연성이 확보될 수 있다. 또한 인덱스와 같은 추가적인 물리적인 객체의 추가적인 생성도 막을 수 있다. 이것은 우리가 관리해야 할 객체의 수가 줄어든다는 것도 의미한다. 실제로 가로로 놓느냐 세로로 놓느냐는 업무에 따라 틀려질 수 있다. 성능이 매우 중요한 경우에는 가로로 놓여질 수도 있다. 세로로 놓는 다는 것은 통합을 의미하며, 대부분은 통합이 유리하다. 가로로 펼쳐 놓다 보면 인덱스를 유지하는 비용이 더 클 가능성이 매우 높기 때문이다. ==== 결론 ==== 정규화를 함으로써 얻는 이점은 매우 많이 있다. 물론 정규화는 논리적인 것이지만 물리적으로 끼치는 영향은 매우 크다. 정규화를 하면 “이상”에 더욱 가까워 질 수 있다. 데이터베이스에서 정규화를 왜 강조하는지 알아야 한다. 정규화는 최고의 성능 향상 도구인 동시에 최고의 무결성 보장과 변화에 대처할 수 있는 최고의 도구이다.