#title Primary Key에 Hash 적용 [[TableOfContents]] ==== 기본 개념 ==== 일반적으로 키 개체집합[* Key Entity Set]에 해당되는 것들이 구현되었을 때에 일련번호[* 실제 개체집합의 명세에는 전혀 도움되지 않는다.]로 PK[* Primary Key]를 만든다. 일련번호는 대리키[* Surrogate Key]다. 대리키를 사용하는 이유는 관계형 모델에서 하위 개체집합들과 키 개체집합 관계를 구현했을 때에 하위 개체집합들의 FK[* Foreign Key] 또는 PK의 일부를 구성하게 되는데에 따른 부담[* 최소한 중복은 이런 FK등을 말한다. 예를 들면 문자열 12바이트 보다는 Int형 4바이트가 덜 부담될 것이다.]을 줄이기 위함이다. 예를 들어 '사원'과 '부양가족'이라는 테이블이 있다고 가정해 보자. '사원'의 '사원번호'는 PK이며, 일련번호다. '부양가족'은 어떤 사원의 부양가족임을 알기 위해서 '사원'과 식별자 관계 또는 비 식별자 관계를 가지게 된다. 예를 들어 '/사원명/ 컬럼은 후보키이고, 사원 A(사원명)의 부양가족 리스트'를 조회하기 위해서는 다음과 같은 SQL 문을 사용하게 된다. {{{#!geshi sql SELECT B.* FROM 사원 A INNER JOIN 부양가족 B ON A.사원번호 = B.사원번호 WHERE A.사원명 = 'A' --사원 'A'의 사원번호가 111임을 알고 있을 경우. --하지만 사워번호는 각각의 사원만 알고 있을 정도이고, 일반적으로는 잘 모른다. --일련번호 자체는 설계속성이므로 의미상으로 따져보면 복잡성을 가중시키게 된다. SELECT * FROM 부양가족 WHERE 사원번호 = 111 }}} 즉, 데이터의 연결을 통해서만 알 수 있는 정보가 된다. 하지만 후보키를 해시함수에 입력하고, 출력된 결과를 '사원번호'로 만든다면 이야기는 틀려진다. '사원번호'를 이와 같은 방법으로 만들었다면 위의 SQL문은 다음과 같이 변경할 수 있을 것이다. {{{#!geshi sql SELECT * FROM 부양가족 WHERE 사원번호 = 해시함수('A') }}} 훨씬 간단해 진다. 요즘의 DBMS는 해시함수를 지원하기 때문에 매우 빠르게 함수 처리를 할 수 있다. 구체적인 예를 들어보도록 하자. ==== 구현 예제1 ==== 다음은 MS-SQL Server를 이용하여 구현한 예제이다. {{{ create table customer ( hash_id int , id varchar(20) , pw varchar(16) , sitecode tinyint ); insert customer values(checksum('yasicom' + CONVERT(varchar(3), 1)), 'yasicom', '1234', 1); insert customer values(checksum('yasicom' + CONVERT(varchar(3), 2)), 'yasicom', '1234', 2); insert customer values(checksum('yasicom' + CONVERT(varchar(3), 3)), 'yasicom', '1234', 3); insert customer values(checksum('yasicom' + CONVERT(varchar(3), 4)), 'yasicom', '1234', 4); go create proc usp_customer_select @id varchar(20) , @sitecode tinyint as select * from customer where hash_id = checksum(@id + CONVERT(varchar(3), @sitecode)); go exec usp_customer_select 'yasicom', 1 exec usp_customer_select 'yasicom', 2 exec usp_customer_select 'yasicom', 3 exec usp_customer_select 'yasicom', 4 }}} ==== 구현 예제2 ==== {{{ create table customer ( hash_id int , id varchar(20) , pw varchar(16) ); insert customer values(checksum('yasicom'), 'yasicom', '1234'); go create proc usp_customer_select @id varchar(20) as select * from customer where hash_id = checksum(@id); go exec usp_customer_select 'yasicom' }}} ==== 장점 요약 ==== 다음과 같은 장점을 가진다. * 일련번호를 없앨 수 있다. * 숫자자체가 의미를 가지게 된다. 하지만 우리는 그 숫자를 알 필요가 없이 해시함수 하나만 알고 있으면 된다. * 인덱스 수를 줄일 수 있다. (id에 인덱스를 생성하지 않아도 된다.) * int형에 대한 인덱스를 생성하므로 인덱스의 크기가 줄어들고 연산속도가 빨라진다. (검색성능향상) 싸이월드와 같은 경우는 고객에 대한 식별자를 '이메일 주소'로 사용하고 있다. 문자열길이도 길지만, 인덱스 크기도 만만치 않을 것이다. 싸이월드에 이러한 방법을 적용한다면 CPU부하를 적어도 5%는 줄어들 것이라 예상된다. (조회, 인덱스 유지보수 비용 등) 단점은 DBMS제품 종속적이라는 것. 졸라 큰 단점이다. ㅡㅡ;;