동물원 - 구역을 나누고 각 구역에 의미를 부여해서 구분. (육식동물, 초식동물, 식물원 등) 내가 원하는 구역에서, 내가 찾고 싶은 동물을 찾으면 된다. => 해싱과 유사!
해시(hash)
버킷(bucket)
일반적으로 해시는 여러개의 버킷을 통해 자료를 저장. 해시함수는 탐색키를 입력받고 저장될 버킷의 ID를 출력해주는 역할을 함.
해시에 있는 데이터는 어떻게 알 수 있을까?
해시함수에다가 탐색키(K3, K7)를 넣으면 그 데이터가 있는 버킷(B3)의 위치를 알려줌.
최선 | 최악 | 일반 |
---|---|---|
![]() | ![]() | ![]() |
여러개의 레코드가 모든 버킷에 균등하게 배분하는것. | 모든 레코드를 하나의 버킷에 배분하는 것. | 균등분배는 거의 이론상으로만 가능하고 좀 몰리는 경향이 있음. |
왜 최악일까?
모든 데이터가 버킷 B4에 들어있음. 그럼 다시 B4에가서 다시 원하는 데이터를 찾아야 함. 이렇게 배분되면 자료를 찾는데 엄청 오래걸리게 됨.
파일구조란 한테이블의 여러 레코드가 디스트의 어느 블럭에 들어갈지 결정하는 것. 이걸 해시함수가 결정하도록 한 것이 "해시파일구조"
K(학번의 끝자리)
인덱스와는 관련없고 자료를 저장하는 방법론에 관한 이야기.
동거자가 너무 많으면 오버플로가 발생 가능
버킷 B2에 들어갈 수 있는 레코드를 초과해서 추가 레코드가 들어오는 경우, B2-1에 넣거나, 그 다음 버킷인 B3에 넣을 수 있음.
만약 탐색키 K5인 레코드를 요구할 때, 해시함수는 B2라고 알려줌. 그 안에 다 뒤졌는데 없으면 연결된 버킷을 메모리에 올려 K5가 나올때까지 더 뒤져봐야 함. 만약 연결된 버킷이 5개이면, 5번의 I/O를 거쳐야 해서 성능 감소가 있게 됨.
오버플로우의 처리 뿐 아니라, 오버플로우의 발생률을 따져보고 이가 발생하지 않는 해시함수를 선택해야 한다.
1. 해시 파일 구조와 동작 방식을 레코드가 아닌 인덱스 엔트리에 적용한 인덱스
이미 디스크 안에 테이블이 저장되어 있고, (각각의 레코드를 버킷 ID에 저장하는 것이 아니라) 레코드에 접근할 수 있는 인덱스 엔트리를 저장할 버킷ID를 구하는데 해시 함수를 사용한다.
각각의 레코드에 대한 인덱스 엔트리를 만들고, 인덱스 엔트리의 탐색기를 해시함수에 적용하고, 그 값을 버킷 0~5사이에 넣는다.
유관순을 찾고 싶어 하는 경우.
끝번호 K=(6 % 5)해시함수 = B1. B1에서 레코드를 찾는다.
윤봉길 학생은 끝번호가 5인데 왜 B2에 있을까?
오버플로우가 발생하여 그 다음 버킷에 넣어둔 것. B0에 빈공간이 없어서 B1에, 거기에도 없어서 B2까지 밀려나서 레코드를 넣어 둠. 이런 경우, 윤봉길의 레코드를 찾으려면 3번의 I/O를 거쳐야만 데이터를 찾을 수 있음.
=> 해시 구조의 크기가 동적으로 결정되는 동적 해싱 기법제안
디렉터리 헤더 3: "모조키의 앞 3비트를 보겠다."
B1
버킷의 헤더 3: (=디렉터리 헤더3) "모조키의 앞 3비트를 보겠다."
앞 3비트가 000인 데이터는 다 저에게 주세요
B3
버킷의 헤더 2: "모조키의 앞 2비트를 보겠다."
앞 3비트가 01인 데이터는 모두 저에게 주세요
B4
버킷의 헤더 1: "모조키의 앞 1비트를 보겠다."
앞의 1비트가 1인 데이터는 모두 저에게 주세요
h(k3) (= 탐색기 k3에 해시함수 적용한 값) 으로 위의 모조키를 만들었다. 이 모조키는 어디로 가야할까? => 3비트가 101 => B4로 가야한다!
💬근데 만약에, 이 모조키를 추가하는 상황이라면 어떨까? 디렉터리 구조에 맞춰 해당 모조키가 B4에 입력되야 할 것이다. 그런데 만약, 여기에 더해, B4가 가득 차 오버플로우가 일어나고 있는 상황이라면?
🔍 정적 해싱에서는 연쇄 버킷을 추가해 넣어주거나, 그 뒤의 버킷에 넣었다.
✔️ 그러나 확장성 해싱(동적 해싱)에서는 그 위의 구조인 디렉터리를 이용해 버킷의 갯수를 추가할 수 있다!
1. 레코드 삽입에 의해 분할된 확장성 해싱 파일
문제가 되는 부분은 B4(시작비트가 1인 모조키를 가진 버킷)이 었다. 이 부분에서 디렉토리를 조정해서, 버킷을 추가했다. 모조키가 1로 시작하는 인덱스 엔트리를 저장하는 버킷을 하나더 추가해 10은 B4에, 11은 B5에 저장되도록 조정했다.
버킷 B1~B3는 어떤 영향도 받지 않았다. 조정되는 것은 B4, B5가 분할된 것 뿐이다. 정적 해싱에 비해 새로운 단계가 추가되어 굉장히 느려질 것 같으나 심각하게 느려지지는 않는다. 디렉토리는 항상 메모리에 적재되어 있어 별도의 디스크 I/O를 발생시키지도 않고, 버킷에 대한 재조정 부분도 향후 오버플로우를 발생시키지 않음을 감안하면 성능저하에 영향이 적은 편이다. 이런 장점으로 확장성 해싱은 자주 사용되는 해싱 기법 중 하나이다.
어떤 해싱을 사용하는게 좋을까?
데이터가 급속도로 증가 & 데이터가 수천배, 수만배 만들어질 수 있는 경우 = 동적해싱 권장
레코드가 항상 유지되는 테이블 = 정적 해싱 권장
탐색키가 너무 많이 중복되면 순차 인덱스, 해싱 인덱스도 효율서이 많이 떨어짐. 이런 경우 비트맵 인덱스를 이용한다.
만약 성별을 인덱스로 사용한다면? 10만명이 있는 데이터에 5만이 여자고 5만이 남자라면 순차 인덱스, 정적 해싱, 동적 해싱 다 효과적이지 못함. 이런 경우 비트맵 인덱스를 사용한다.
1. i번째 레코드가 컬럼 A에 해당 값을 가지면 비트맵의 i번째 비트를 1로, 그렇지 않으면 0으로 설정
비트열: 특정 컬럼이 가질 수 있는 값들의 갯수만큼 만들어짐.
< 성별에 대한 비트맵 >
< 성적에 대한 비트맵 >
성별이 남자이고 성적이 B인 학생의 정보를 출력
SELECT * FROM 학생 WHERE 성별 ='남자' AND 성적 ='B'
성별의 '남자'와 성적의 'B'의 비트열에 대한 비트 논리곱 연산을 수행
최종적으로 and연산(조건이 or이면 or연산을 해준다)을 수행한 비트열을 가지고, 값이 1인 레코드들이 조건을 만족하는 레코드임을 알 수 있다. 해당 블럭들을 메모리에 적재시켜 결과를 줌으로써 인덱스 역할을 수행할 수 있는 것이 비트맵 인덱스다.