[PostgreSQL] 해시 인덱스(Hash Index)에 대해서 - 컴도리돌이
쿼리를 작성하고 나서 실행 계획을 확인하다 보면 가끔 Bitmap Index Scan이나 Hash Join이라는 용어를 접하게 돼요. 해시 인덱스가 사용된 걸 보고는 이제 데이터 조회가 더 빠르겠지?라고 기대했는데, 의외로 성능이 좋지 않을 때가 많더라고요 🤔 그럴 때마다 해시 인덱스를 사용되었는데, 왜 이렇게 느리지?라는 생각만 들곤 했지만, 한 번도 검색해보지 않는 과거의 저를 반성하며 오늘의 나는 해시 인덱스에 대해 깊이 알아가는 시간을 가지려고 해요 😊
해시 인덱스는 PostgreSQL에서 효율적인 데이터 검색을 위해 제공하는 여러 인덱스 유형 중 하나이에요. 이 인덱스는 특정한 키 값에 대해 매우 빠른 조회 성능을 제공하는데, 그 이유는 해시 함수를 사용하여 데이터를 처리하기 때문이죠. 여기서 도대체 해시 함수를 처리하면 왜 데이터가 빠르게 처리되어서 조회가 될까요? 🙄
해시 함수는 입력된 키 값을 고정된 크기의 고유한 해시 값으로 변환해 줍니다. 이 해시 값은 인덱스 내부의 버킷이라는 메모리 공간에 저장되며, 같은 해시 값을 가진 데이터는 동일한 버킷에 위치하게 되죠. 이렇게 되면, 해시 인덱스는 키 값을 직접적으로 비교하지 않고 해시 값을 통해 비교하기 때문에 조회 성능이 크게 향상됩니다.
SELECT * FROM users WHERE username = 'john_doe'
예를 들어, 위와 같은 테이블에서 특정 이름을 가진 컬럼을 조회한다고 가정해 보면, 해시 인덱스를 사용하기 전에는 이 쿼리가 테이블 전체를 스캔하며 일치하는 레코드를 찾아서 조회합니다. 실제로 조회하는 seq scan으로 전체 테이블을 조회하게 되죠. 하지만 여기서 해시 인덱스를 사용하면 username 필드에 대해 해시 값으로 변환된 인덱스를 검색하여 일치하는 레코드를 즉시 찾아내줍니다.
해시 인덱스를 사용하는 방법은 간단해요. 먼저 특정 컬럼에 해시 인덱스를 생성하는 SQL 명령을 실행해 줍니다.
CREATE INDEX ON users USING hash (username)
이렇게 인덱스를 생성한 후 동일한 쿼리를 실행하면, 해시 인덱스가 자동으로 사용되어 훨씬 빠르게 결과를 반환하게 됩니다. 단, 해시 인덱스는 정확히 동일한 값에 대해서만 유효하기 때문에 범위 검색에는 적합하지 않으며, 따라서 특정 값을 정확히 일치시키는 쿼리에서만 큰 효과를 발휘합니다.
따라서 특정 값을 정확히 일치시키는 쿼리에서만 큰 효과를 발휘하는 거죠. 장점으로는 정확한 일치 검색에 대해 매우 빠른 성능을 제공하며, 단점으로는 해시 인덱스가 범위 검색에는 적합하지 않으며 특정 상황에서는 Btree 인덱스보다 오버헤드가 발생할 수 있어요
또한 해시 인덱스는 WAL을 지원하지 않아 장애 복구 시 인덱스가 재구성되어야 하는 단점이 있어요. 이러한 특성을 고려할 때, 해시 인덱스는 특정 시나리오에서만 선택하는 게 좋을 거 같아요 🤔
이번 글을 작성하면서 해시 인덱스와 조금 더 친해지는 계기가 되었고, 성능 문제로 인덱스를 설정하는 일이 생길 때 해시 인덱스를 고려하면서 설계를 해야겠어요 😂