본문으로 건너뛰기
6.2 Hash 인덱스

6.2 Hash 인덱스

Hash 인덱스는 등호(=) 비교만을 위한 인덱스입니다. 키를 해시해서 버킷에 매핑하므로 룩업이 O(1)에 가깝습니다. 그러나 범위·정렬·prefix 모두 안 되고 운영 메리트가 작아, 일상에서는 거의 안 쓰입니다. PG 10에서야 WAL이 붙어 crash-safe하고 복제도 되는 운영 가능한 상태가 되었다는 점도 채택을 더디게 만든 이유.

언제 검토 가치가 있는가

시나리오Hash가 좋을 수 있나
매우 큰 텍스트(키 길이 100B+)의 정확 일치 룩업인덱스 크기가 B-tree보다 작아질 수 있음
캐시 키 같은 단순 등호 쿼리OK, 단 B-tree로도 충분히 빠름
범위·정렬·prefix·ORDER BYB-tree
join, unique 제약B-tree (Hash는 unique 미지원)

운영 권장은 B-tree가 디폴트, Hash는 명확한 이유가 있을 때만.

생성

CREATE INDEX idx_users_email_hash ON users USING hash(email);

조회는 평소처럼:

SELECT * FROM users WHERE email = 'a@b.com';

EXPLAIN에서는 Index Scan using idx_users_email_hash 형태로 나타납니다.

제약과 한계

제약메모
=만 지원<, >, BETWEEN, ORDER BY 모두 불가
Unique 미지원PK·UNIQUE constraint를 hash로 못 만듦
Multi-column 미지원한 컬럼만. 다중은 표현식 인덱스로 묶거나 B-tree
Index-only scan 미지원VM 활용 불가
WAL 지원PG 10+

성능 비교 — B-tree와의 차이는?

실제 운영에서는 B-tree와의 차이가 크지 않습니다. PG의 B-tree가 매우 잘 최적화돼 있어 등호 룩업도 O(log n) ≈ 23 페이지 비용입니다. Hash가 이론적으로 O(1)이지만 페이지 12를 따라가는 비용은 비슷.

측면B-treeHash
룩업 비용O(log n), 보통 2~4 페이지O(1), 보통 1~2 페이지
인덱스 크기키 + ctid + 메타해시값 + ctid + 메타 — 긴 키에서 작아짐
범위·정렬가능불가
운영 도구 지원완전일부 도구(BLOAT 추정 등) 약함

짧은 키(int, uuid)는 차이 무시할 만 함. 매우 긴 키일 때만 hash가 크기 이점.

운영 시 고려 사항

-- Hash 인덱스는 collision이 늘면 BLOAT
\d+ users
-- Indexes:
--     "idx_users_email_hash" hash (email)

pg_class.relpages로 크기 추적합니다. dead entry는 VACUUM이 정리하지만, B-tree만큼 다듬어진 도구가 적다 — 운영 표준에서 빠지는 이유.

표현식 인덱스로 hash 효과 내기

여러 컬럼 등호 룩업이 빈번하면 표현식 hash 인덱스가 가능:

CREATE INDEX idx_users_composite_hash
  ON users USING hash((tenant_id::text || ':' || email));

-- 쿼리도 같은 식
SELECT * FROM users WHERE tenant_id::text || ':' || email = '42:a@b.com';

다소 어색합니다. 대부분의 경우 multi-column B-tree가 더 자연스럽고 빠릅니다.

Hash 인덱스를 쓰기 전에 정말 필요한지 한 번 더 고민. 매우 긴 키의 등호 룩업이라는 구체적 이유가 있을 때만. 일반 OLTP는 B-tree가 답입니다.

진단 — Hash 인덱스 사용 추적

SELECT t.relname AS table, i.indexrelname AS index, i.idx_scan
  FROM pg_stat_user_indexes i
  JOIN pg_index x ON i.indexrelid = x.indexrelid
  JOIN pg_class c ON x.indexrelid = c.oid
  JOIN pg_am a ON c.relam = a.oid
  JOIN pg_class t ON x.indrelid = t.oid
 WHERE a.amname = 'hash';

idx_scan = 0이면 사용 안 됨 — 정리 후보입니다.

정리

  • Hash 인덱스는 등호 룩업 전용
  • PG 10+에서야 운영 가능 (WAL·replication 지원)
  • 짧은 키에서는 B-tree와 성능 차이 거의 없음
  • 매우 긴 키의 정확 일치 룩업 외에는 B-tree가 표준
  • Unique, multi-column, index-only scan, 정렬 모두 불가
  • 운영에서는 확실한 이유가 있을 때만 채택

다음 절(6.3)에서는 공간 데이터·범위 타입에 강한 GiST와 SP-GiST를 봅니다.