이미 인덱스 이론에 대해 알아봤고, 인덱스 종류도 익혔지. 인덱스 만드는 법, 지우는 법, 그리고 배열이나 JSONB 같은 복잡한 데이터 타입 인덱싱도 배웠어. 이제 진짜 중요한 건, 내 상황에 딱 맞는 인덱스를 어떻게 고르냐는 거야 — 잘못 고르면 진짜 골치 아파질 수 있거든.
네 데이터베이스를 도서관이라고 생각해봐. 쿼리는 책을 찾으러 오는 방문자야. 만약 책이 바닥에 막 굴러다니면, 찾는 게 완전 미로 찾기지. 인덱스는 잘 정리된 책장이나 카탈로그처럼, 필요한 걸 빠르게 찾게 도와주는 거야. 시간 낭비 없이!
근데 잘못된 책장이나 카탈로그를 쓰면, 예를 들어서 범위 검색이 필요한데 HASH 인덱스를 쓴다? 이건 도서관 사서가 책 제목으로 찾으려는데 연도별 카탈로그만 있는 거랑 똑같아 — 찾는 데 시간 엄청 걸리고, 다들 불평하지. 데이터베이스에선 이게 느린 쿼리랑 시스템 부하로 나타나.
오늘은 어떻게 하면 쿼리가 날아다니고, 데이터베이스가 힘들지 않게 인덱스를 고를 수 있는지 알려줄게. 잘못 고르면 진짜 답도 없어: 쿼리 느려지고, 리소스 다 잡아먹고, 사서(PostgreSQL)는 멘붕 온다.
인덱스 선택 기준: 체크리스트
인덱스 고를 때, 아래 질문에 답해봐:
- 이 컬럼의 데이터 타입이 뭐야?
- 예를 들어, 숫자
INTEGER,FLOAT는 보통B-TREE인덱스가 좋아. 배열이면GIN, 텍스트 필드는 상황에 따라 달라.
- 예를 들어, 숫자
어떤 쿼리를 제일 자주 써?
WHERE field = value? 딱 맞는 값 찾기? 그럼B-TREE나HASH가 잘 맞아.- 배열이나 JSONB 검색?
GIN쪽을 봐봐. - 지오데이터, 범위 검색?
GiST생각해봐.
데이터에 무슨 일이 자주 일어나?
- 테이블에 insert, update가 자주 일어나면, 인덱스 너무 많이 만들지 마. 오버헤드가 커져.
유니크 보장해야 해?
- 그럼
UNIQUE속성 있는 인덱스를 써야 해.
- 그럼
케이스: 실제 인덱스 선택 예시
실제 시나리오 몇 개 볼까?
1. 단순한 값 일치 검색
학생 데이터베이스에서 이메일로 학생을 빠르게 찾고 싶어:
SELECT * FROM students WHERE email = 'student@example.com';
여기서 중요한 건? 값 일치 검색이야. B-TREE 인덱스가 딱이야, 정확히 일치하는 값 찾는 데 최적화되어 있거든.
CREATE INDEX idx_students_email ON students (email);
이메일이 유니크해야 한다면:
CREATE UNIQUE INDEX idx_students_email_unique ON students (email);
2. 범위 검색
이번엔 18살 넘은 학생을 찾고 싶다고 해보자:
SELECT * FROM students WHERE age > 18;
범위 검색엔 B-TREE도 아주 좋아. 순서대로 찾는 구조라서.
CREATE INDEX idx_students_age ON students (age);
3. 배열 필터링
courses 테이블이 있고, 한 컬럼에 수강 학생 ID 배열이 들어있어. ID가 123인 학생이 듣는 모든 코스를 찾고 싶어.
SELECT * FROM courses WHERE student_ids @> ARRAY[123];
이런 쿼리엔 GIN 인덱스가 최고야. 배열에 최적화되어 있거든.
CREATE INDEX idx_courses_students_ids ON courses USING gin (student_ids);
4. JSONB에서 데이터 뽑기
JSONB 데이터가 들어있는 테이블이 있고, 주문 정보가 저장돼 있어. "Moscow" 도시의 고객 주문을 찾고 싶어:
SELECT * FROM orders WHERE data->>'city' = 'Moscow';
여기선 GIN 인덱스가 좋아. JSONB의 키와 값 검색에 효율적이야.
CREATE INDEX idx_orders_data ON orders USING gin (data);
5. 지리 정보 데이터
지리 정보 다룰 때, 예를 들어 특정 반경 안의 모든 포인트를 찾고 싶으면 GiST 인덱스를 써. 이 인덱스는 지오메트리, 범위에 강해.
CREATE INDEX idx_locations_geom ON locations USING gist (geom);
다양한 인덱스 성능 비교
이메일로 학생 찾는 실제 예시를 들어볼게. 테이블에 100만 개 레코드가 있어. 인덱스 없이, 그리고 여러 인덱스로 쿼리 실행해보자:
| 시나리오 | 실행 시간 |
|---|---|
| 인덱스 없음 | 1500 ms |
B-TREE 인덱스 |
2 ms |
HASH 인덱스 |
3 ms |
결론: 이 경우 B-TREE 인덱스 쓰면 쿼리 속도가 500배 이상 빨라져.
인덱스 선택 실수
가장 흔한 실수 — "혹시 몰라서" 인덱스 막 만드는 거야. 예를 들어, 테이블의 모든 컬럼에 인덱스 걸었더니 insert 성능이 뚝 떨어져. 인덱스는 만능 도구가 아니야. 잘 쓰면 강력하지만, 잘못 쓰면 오히려 해가 돼.
또 다른 흔한 실수 — 잘못된 인덱스 타입 선택. 예를 들어, 범위 검색에 HASH 인덱스를 쓰면 쿼리가 갑자기 엄청 느려져. HASH 인덱스는 정확히 일치하는 값만 빠르게 찾을 수 있거든.
인덱스 선택 꿀팁
- 값 일치 검색이나 정렬을 자주 한다면
B-TREE써. - 정확히 일치하는 값만 찾고, 메모리 아끼고 싶으면
HASH도 괜찮아. - 배열이나 JSONB 다룬다면
GIN이 답이야. - 범위나 지리 정보엔
GiST를 써봐.
그리고 제일 중요한 팁: 쿼리 분석 꼭 해! EXPLAIN이나 EXPLAIN ANALYZE로 PostgreSQL이 인덱스를 어떻게 쓰는지, 개선할 점이 뭔지 확인해봐.
EXPLAIN ANALYZE
SELECT * FROM students WHERE email = 'student@example.com';
오늘은 여기까지! 이제 인덱스 고르는 법, 진짜 마스터했지? 쓸데없는 인덱스 만들지 말고, 항상 성능에 어떤 영향이 있는지 체크해!
GO TO FULL VERSION