CodeGym /행동 /SQL SELF /과도한 인덱싱의 문제

과도한 인덱싱의 문제

SQL SELF
레벨 38 , 레슨 2
사용 가능

인덱스는 DB를 훨씬 빠르게 만들어주는 멋진 방법이긴 한데, “최고가 항상 좋은 건 아니다”라는 말 알지? 모든 인덱스가 도움이 되는 건 아니고, 너무 많으면 오히려 해가 될 수도 있어. 좀 이상하게 들릴 수 있지만 진짜 그래. 같이 알아보자!

큰 도서관을 상상해봐. 책을 찾으려고 여러 카탈로그가 있어 — 예를 들면, 저자별, 장르별, 출판연도별. 이런 카탈로그는 원하는 책을 빨리 찾게 도와주지. 근데 만약 카탈로그가 너무 많아진다면 — 예를 들어, 제목의 모든 단어나 세부사항마다 하나씩 있다면? 오히려 헷갈리고, 찾는 데 시간 더 걸리고, 공간도 엄청 차지하고, 사서가 계속 리스트를 업데이트하느라 힘들 거야.

DB에서 인덱스도 비슷해: 원하는 데이터를 빨리 찾게 해주지만, 너무 많으면 레코드 추가나 수정할 때마다 인덱스도 다 업데이트해야 해서 일이 엄청 많아져. 디스크 공간도 많이 먹고. 게다가 인덱스가 너무 많으면, DB가 어떤 인덱스를 써야 할지 헷갈릴 수도 있어.

그래서 도서관 카탈로그처럼, 인덱스도 적당히 필요한 것만 있는 게 좋아. 쓸모없는 인덱스 수십 개보단, 진짜 필요한 몇 개가 훨씬 낫지.

이제 "PostgreSQL 탐정놀이" 해보자. 예를 들어, 한 컬럼에 인덱스를 세 개 만들었다고 해봐. 성능이 좋아질 거라 생각해서 그랬겠지. 근데 상상해봐:

  • 테이블이 학생 리스트고, 인덱스가 세 개면, 학생 한 명 추가할 때마다 인덱스도 세 번씩 업데이트해야 해. 이게 과연 “빠른” 걸까?
  • 이런 테이블이 10개고, 다 인덱스로 도배되어 있다면? DB 전체 성능이 바닥을 칠 거야.

과도한 인덱싱 문제, 어떻게 알 수 있을까?

가장 먼저 할 일은, 현재 인덱스가 어떻게 되어 있는지 보는 거야. PostgreSQL에서는 이 명령어로 확인할 수 있어:

\d 테이블_이름

이 명령어는 테이블, 컬럼, 그리고 연결된 인덱스를 보여줘. 한 테이블에 인덱스가 엄청 많으면, 이미 문제의 신호야.

또 하나 유용한 도구는 시스템 뷰 pg_stat_user_indexes야. 이걸로 인덱스가 얼마나 자주 쓰였는지 볼 수 있어서, “죽은 인덱스”가 뭔지 알 수 있어:

SELECT
    relname AS table_name,
    indexrelname AS index_name,
    idx_scan AS index_scans
FROM
    pg_stat_user_indexes
WHERE
    idx_scan = 0;

idx_scan이 0이면, 그 인덱스는 한 번도 쿼리에서 안 쓰였다는 뜻이야. 이런 인덱스는 바로 삭제 후보!

과도한 인덱싱 예시

유저 테이블을 상상해보자:

CREATE TABLE users (
    user_id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE,
    username VARCHAR(50),
    created_at TIMESTAMP DEFAULT NOW()
);

그리고 인덱스가 세 개 있다고 해보자:

-- email 인덱스
CREATE INDEX idx_users_email ON users (email);

-- username 인덱스
CREATE INDEX idx_users_username ON users (username);

-- created_at 인덱스
CREATE INDEX idx_users_created_at ON users (created_at);

이제 우리가 자주 하는 쿼리를 보자:

  1. email로 유저 찾기.
  2. username으로 유저 찾기.
  3. created_at으로 유저 정렬하기.

인덱스가 다 쓸모 있어 보이지? 근데 만약 이런 쿼리가 진짜 드물게(예를 들어, 일주일에 한 번)만 실행된다면, 인덱스 만드는 게 별 의미 없어. 게다가 일부 인덱스는 아예 안 쓰일 수도 있고, 그러면 데이터 삽입/업데이트만 느려져.

예를 들어, users 테이블에 이런 데이터가 있다고 해보자:

user_id email username created_at
1 alex.lin@mail.com alexlin 2024-06-15 10:23:00
2 anna.min@mail.com annamin 2024-06-16 12:47:00
3 otto.song@mail.com ottosong 2024-06-17 08:30:00
4 maria.chi@mail.com mariachi 2024-06-18 14:10:00

만약 username으로 검색하는 쿼리가 거의 없다면, idx_users_username 인덱스는 한 번도 안 쓰이고(idx_scan = 0), 최적화를 위해 삭제해도 돼.

즉, 인덱스는 진짜 좋은 도구지만, 똑똑하게 써야 해. 꼭 필요한 것만, 자주 쓰는 것만 남기는 게 좋아.

과도한 인덱싱 피하는 법

  1. 사용 중인 인덱스 분석하기. 아까 말한 것처럼, pg_stat_user_indexes로 인덱스 사용 통계를 확인해봐. 거의 안 쓰는 인덱스는 삭제해도 돼:
DROP INDEX IF EXISTS 인덱스_이름;
  1. 자주 쓰는 쿼리만 인덱스 만들기. 인덱스 추가하기 전에 스스로에게 물어봐:
  • 이 컬럼이 WHERE, ORDER BY, GROUP BY에 자주 쓰이나?
  • 테이블 데이터가 많은가?
  • 인덱스 없으면 쿼리가 진짜 느린가?

이 중 하나라도 “아니오”라면, 인덱스는 굳이 필요 없을 수도 있어.

  1. 복합 인덱스 사용하기. 여러 컬럼을 한 쿼리에서 자주 쓴다면, 각각 따로 인덱스 만들지 말고 복합 인덱스를 만들어봐:
CREATE INDEX idx_users_email_username ON users (email, username);

이렇게 하면 email 이랑 username을 동시에 필터링하는 쿼리가 빨라져.

  1. 기존 인덱스 정기적으로 점검하기. DB가 커지면 쿼리 패턴도 바뀔 수 있어. 예전에 유용했던 인덱스가 지금은 필요 없을 수도 있지. 가끔씩 인덱스 점검해서, 안 쓰는 건 과감히 삭제하자.

인덱스 최소화 예시

다시 users 테이블로 돌아가보자. 세 개의 인덱스를 이렇게 최적화할 수 있어:

  • created_at 인덱스는, 이 컬럼으로 정렬을 거의 안 한다면 빼버리자.
  • emailusername에 각각 인덱스 만들지 말고, 복합 인덱스 하나로 합치자:
CREATE INDEX idx_users_email_username ON users (email, username);

정리: 밸런스의 비밀은?

프로그래밍에서 자주 나오는 미니멀리즘 원칙이 여기서도 통한다: “적을수록 좋다”. 모든 컬럼에 인덱스 다는 건 의미 없어. 인덱스가 왜 필요한지, 쿼리 성능에 진짜 도움이 되는지 생각해보고 추가하자. 실용적으로 접근하고, 인덱스를 마구잡이로 추가하는 게 아니라, 그 영향과 효율을 이해하고 똑똑하게 쓰는 게 진짜 개발자야.

이제 이 도구를 잘 쓰면, 과도한 인덱싱이라는 재앙을 막고, 네 DB를 치타처럼 빠르게 만들 수 있어. 쓸데없는 인덱스 잔뜩 달고 느린 거북이처럼 만들지 말고!

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION