컬럼 데이터 형식을 어떻게 결정하는가? 직감으로 보면 알 수 있나? 아니면 기준을 가지고 하는가? 훈련 없는 직감은 아차 하는 실수를 낳을 수 있다. 기준을 가지고 컬럼 데이터 형식을 판단하는 훈련을 여러 번 하다 보면 훈련 받은 직감이 생긴다. 이 직감은 객관적인 판단기준이 휘리릭 ~ 하고 계산되고 나온 결과이다. 여러분이 이러한 훈련을 하는데 필요한 기준이 무엇인지를 설명한다.
 
첫 번째 기준은 “논리적인 데이터 형식 먼저 생각하라.” 논리적인 데이터 형식이라는 것은 해당 컬럼 혹은 변수가 문자(character), 숫자(Number), 날짜(Datetime), 바이너리(Binary) 카테고리 중 어디에 속하는가 이다.
 
모든 데이터 형식들은 이 4가지 범주 안에 반드시 속하게 되어있다. 그리고 이 4가지 데이터 형식들은 모두 문자열(String)에서 파생되었다. 따라서 모든 값은 문자열로 표현될 수 있다. 예를 들어 숫자도 문자열로 표현될 수 있다. 2는 정수(Int) 값이지만 ‘02’ 혹은 ‘2’ 라는 문자열 값으로 저장할 수 있다. ‘2008-01-01’도 문자열로 저장이 가능하며, ;0x080000000100’ 와 같은 바이너리도 문자열로 저장할 수 있다. 따라서 모든 데이터 형식은 문자열이라고 볼 수 있고, 이를 Char 혹은 Varchar 형식에 저장할 수 있다. 원래의 데이터베이스는 이렇게 모든 데이터 형식을 문자열 형식 하나에 저장하였다. 하지만 시간이 흐르면서 여러 가지 형태의 데이터 형식들을 필요로 하게 되면서 이렇게 세분화된 것이다.
 

문자열 보다 다른 데이터 형식을 사용하는 첫 번째 이유는 문자열 보다 적은 바이트 수로 값을 표현할 수 있다는 것이다. ‘10000’은 문자열로는 5바이트이지만, 정수형으로는 4바이트로 표현 가능하다. 날짜도 마찬가지이다. 두 번째 이유는 데이터 연산을 위해서 데이터 형식을 규정 짓고 싶기 때문이다.
 

정수는 사칙연산을 포함해서 다양한 수식 연산을 할 수 있고, 날짜도 더하거나 뺄 수 있다. 하지만 문자열은 고작해야 문자열을 자르고, 붙이고, 치환하는 작업만이 가능할 뿐이다. 내재적인 숫자 타입들은 이러한 연산 보다는 더하고, 빼고, 나누고, 곱하는 연산이 더 중요하다. 따라서 세분화된 데이터 형식은 문자열로는 수행하기 힘든 다양한 형식들을 이용할 수 있다. 
 

세 번째는 데이터 형식 각각이 값에 대한 검사 조건(Check constraint)으로서 사용된다는 것이다. 예를 들어, 정수형 컬럼에 ‘가나다’ 라는 문자열을 포함할 수는 없다. 오직 정수 형식의 데이터들만이 포함될 뿐이다. 날짜 형식도 마찬가지이다. 날짜 커럼에는 날짜 데이터 형식에 맞는 값들만이 들어갈 뿐이고, 벗어나는 값들은 오류를 발생한다. 이러한 검사 조건으로 컬럼형식을 사용할 수 있다.
 
① 적은 바이트 수로 값을 표현
② 연산 가능한 값을 위해
③  값의 형식 검사를 위해


참고서적:Deep Inside T-SQL


크리에이티브 커먼즈 라이센스
Creative Commons License 이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
트랙백 주소: http://ggoma.isblog.net/trackback_post_448.aspx

댓글을 달아 주세요

앞의 내용에서 사용한 힙 테이블을 기준으로 클러스터드 인덱스만을 가지는 테이블을 만들어 보자. 방법은 넌 클러스터드의 경우와 유사하며, 다만 리프 레벨 페이지가 직접 데이터 페이지가 된다는 점만이 다르다.


그림을 보면 실제 데이터 페이지 자체를 정렬해서 이것이 리프 레벨노드로 사용되고, 그 위에 넌 리프 레벨 노드와 루트 노드가 생성되었음을 알 수 있다. 데이터 페이지가 많지 않아 중간 레벨 노드들은 없었다. 기존 RID 대신에 최종 레벨 노드들은 인덱스 페이지의 첫 번재 로우값을 가지게 된다. 포인터 점프 대신에 데이터 페이지의 첫 첫번째 컬럼 값을 가지고 해당 데이터 페이지로 이동하여 데이터 페이지의 첫 번째 값부터 순차적으로 읽어 들이게 된다.
 
클러스커드 인덱스에서 값을 조회해보자. 검색할 데이터는 번호가 4번인 데이터이다. 역시 데이터 검색은 루트 노드부터 시작하게 된다. 루트노드에서 값이 4번인 것은 데이터 페이지 1에 있다는 것을 알 수 있다. 중간 레벨 노드들이 많았다면 아마도 몇 가지 레벨에 거쳐서 이러한 탐색 단계들을 진행해야만 할 것이다.


참고서적:Deep Inside T-SQL

크리에이티브 커먼즈 라이센스
Creative Commons License 이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
트랙백 주소: http://ggoma.isblog.net/trackback_post_447.aspx

댓글을 달아 주세요

아래<그림>은 클러스터드 인덱스가 없는 넌 클러스터드를 나타낸다. 첫 번째 레벨과 두 번째 레벨까지의 노드들은 인덱스 페이지들이며, 가장 하위의 것은 트리의 리프 레벨 노드들이 아니라 무작위로 저장되어 있는 데이터 페이지들이다. 그림에서는 intermediate레벨 노드들은 존재하지 않고 루트 노드와 리프노드로 직접 구성되어 있다. 리프 노드들은 데이터 페이지로의 포인터(이를 Row ID 혹은 RID(Relative Identifier)라고 부르기도 한다.)를 링크하고 있다.


이렇게 실제 데이터를 가져오기 위해서 리프 노드에서 데이터 페이지로 이동하는 것을 포인터 점프(Pointer Jump)라고 부른다. 클러스터드 인덱스에서는 리프 레벨이 데이터 페이지이므로 이러한 포인터 점프가 필요 없다. 포인터 점프는 쿼리의 퍼포먼스에 영향을 미칠 수도 있다.
 

좀더 실제적인 예를 가지고 살펴보자 우선 클러스터드든 넌 클러스터드든 아무런 인덱스도 설정되지 않은<그림1>와 같은 테이블이 있다. 이렇게 아무런 인덱스도 설정되지 않은 테이블을 힙 테이블(Heap Table)라고 한다. 데이터는 정렬되어 있지 않고 무작위로 들어 있다. 컬럼은 번호, 이름, 주소, 나이 순으로 되어 있고, 모두 11개의 로우들로 구성되어 있는 간단한 주소 테이블이다.
 

                                                            <그림1>

이 테이블의 데이터 페이지 구성은 <그림2>과 같으며, 무작위 순으로 되어 있다. (예제를 간단히 표현하기 위해서 하나의 데이터 페이지에는 모두 4개의 로우들만 들어 갈 수 있다고 가정 하였다)

                                                             <그림2>
 
모두 3개의 데이터 페이지로 구성되어 있으며 페이지 1과2는 모두 채워져 있고 페이지 3은 여분으로 로우 하나가 더 추가 될 수 있다.(실제 상황이라면 이렇게 로우 개수를 기준으로 데이터 페이지가 채워지는 것은 아니다. 당연히 로우가 가진 실제 데이터에 맞추어서 저장 되어진다.)
 
데이터 페이지에 저장된 것은 컬럼의 정열 순서와는 아무런 상관도 없다. 순전히 데이터가 추가된 순서라고 할 수 있다. 예를 들어 번호가 1인 김수영 로우가 가장 먼저 Insert 되고, 다음에 5번인 김시원 데이터가 저장되었다.
 
이를 번호 순으로 정렬하면 <그림3>과 같은 리스트가 만들어진다. 옆에 있는 Row ID는 앞에 강좌에서 설명한 것처럼 데이터 파일, 데이터페이지 번호, 로우 번호로 구성되는 것으로써 그림에서 번호 2의 경우 ‘1-1-1’ 1번 데이터 파일에 1번 페이지의 1번 로우라는 데이터 페이지 포인터 값을 가상으로 표현한 것이다. 일단 정렬된 리스트가 있으면 이를 인덱스 페이지로 구성하는 것은 매우 간단하다.

 

넌 클러스터드 인덱스를 만드는 것은 어려운 일이 아니다. 인덱스 컬럼으로 선택된 컬럼들을 기준으로 데이터 페이지를 정렬해서 이를 B-Tree로 구성하고, 리프 레벨에서는 실제 데이터페이지로 링킹 될 수 있도록 RID를 매팅한다.


클러스터드 인덱스가 없는 넌 클러스터드 인덱스 상황에서 원하는 값을 찾을 때 어떻게 수행되는지를 알아보자. 인덱스의 구축은 최하위 레벨인 리프 레벨에서부터 루트 노드로 상향식으로 이루어졌지만, 탐색은 정반대로 루트 노드에서 리프 레벨 노드로 이루어진다. 우선 번호 15를 가지고 루트 노드의 로우들과 비교한다. 

여기서 로우 아이디를 기준으로 포인터 점프(Pointer Jump)를 한다. 포인터 점프는 데이터 페이지로 링크하는 것이다.




크리에이티브 커먼즈 라이센스
Creative Commons License 이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
트랙백 주소: http://ggoma.isblog.net/trackback_post_446.aspx