인덱스 설계

BaeBae·2025년 12월 9일

친절한 SQL 튜닝

목록 보기
8/8
post-thumbnail

1️⃣ 인덱스 설계가 어려운 이유

📌 인덱스는 많으면 느려지고 적으면 못 찾는다

  • 인덱스가 많아질수록 DML 성능 저하 (Insert / Update / Delete 시 인덱스도 수정됨)
  • DB 용량 증가 (인덱스도 저장해야 하므로)
  • 운영 비용 증가
  • 인덱스 Split(블록 분할) 발생 → 성능 저하

즉, 인덱스는 “많으면 독, 적어도 독”이므로 정확한 선택 기준이 필요하다!!

2️⃣ 가장 중요한 두 가지 선택 기준

📌 '=' 조건 먼저, 자주 쓰는 컬럼 먼저

  1. 항상 사용되는 조건절 = 가장 앞 컬럼
  2. 항상 사용되는 조건 중에서도 자주 조회되는 컬럼 = 더 앞

3️⃣ 스캔 효율성 이외의 판단 기준

📌 인덱스는 '자주 쓰는가'가 가장 중요

인덱스 설계 기준은 단순히 스캔 효율뿐 아니라 아래를 모두 고려해야 함

  • 쿼리 수행 빈도
  • 업무 중요도
  • 컬럼 선택도(카디널리티)
  • 데이터량
  • 인덱스 개수 / 부하
  • 저장 공간 및 비용

4️⃣ 공식을 초월한 전략적 설계

📌 공식이 아니라 전략이 필요함!

대표적인 전략

  • ‘=’ 조건은 선두 컬럼
  • 날짜(BETWEEN)는 뒤쪽
  • 자주 쓰는 필터는 뒤에 추가
  • 실제 액세스 경로를 보고 결정
    ➡️ 실제 패턴을 기준으로 줄여나가는 것이 정답이다.

5️⃣ Sort 연산을 생략하기 위한 컬럼 추가

📌 ORDER BY가 있다면 정렬 컬럼도 인덱스에 넣기

💡 Main Idea

ORDER BY 절이 빈번하게 등장할 때
→ 인덱스에 정렬 컬럼(ORDER BY 컬럼)을 넣으면 Sort 연산을 생략 가능

인덱스 순서 구성 시 고려할 점

  • '=' 조건 컬럼은 ORDER BY 컬럼 앞뒤 상관 어디나 OK!
  • '='이 아닌 조건절 컬럼은 반드시 ORDER BY 컬럼보다 뒤에 배치해야 정렬 생략 가능

IN 조건은 '='이 아니다

  • IN ('A','O') 는 ='A' + ='O' 의 UNION ALL 형태로 실행되어 Sort 불가능
  • 즉, IN 조건 = 범위 조건에 가깝기 때문에 선두 컬럼으로 쓰기엔 비효율적일 수 있음

6️⃣ 결합 인덱스 선택도

📌 선택도(선택행수/전체행수)가 낮으면 인덱스 가치가 있다!

❓ 선택도란?

  • 선택도 = 선택되는 행 수 / 전체 레코드 수
  • 선택도 낮음
    • 걸리는 행이 적다
    • 인덱스 효율 높음
  • 선택도 높음
    • 걸리는 행이 많다
    • 인덱스 효율 떨어짐

❗ 결론

  • 비율이 낮을수록 좋다
  • 즉, 조건 걸었을 때 행이 적게 선택될수록 좋은 컬럼

7️⃣ 중복인덱스 제거

✔ 1. 완전 중복 인덱스

  • A 인덱스 컬럼 전체가 B 인덱스에 그대로 포함됨
  • A는 삭제 가능

예시

  • A = (고객ID)
  • B = (고객ID, 주문일자)
  • A는 완전 중복으로 삭제 가능

✔ 2. 불완전 중복 인덱스

💡 선두 컬럼이 같지만 뒤 컬럼이 달라서 목적이 각각 다른 인덱스들로 삭제할지 유지할지 업무 패턴 기반으로 판단해야 하는 인덱스

  • 앞쪽 컬럼은 같지만 뒤쪽 컬럼이 다르게 붙은 인덱스들
  • 둘 다 존재할 필요는 없지만 상황 따라 하나만 골라야 하는 경우
  • 즉 앞에 컬럼은 같아 중복처럼 보이지만 뒤 컬럼이 달라서 목적이 다르기 때문에 판단이 필요함

예시

  • X01: 계약ID + 청약일자
  • X04: 계약ID + 데이터생성일시
  • X02: 계약ID + 보험개시일자
  • X03: 계약ID + 보험종료일자
✔ 공통점

모두 계약ID가 앞에 있음 → 겉으로 보면 중복 느낌

✔ 차이점

뒤에 붙은 컬럼이 전부 다름

  • 누군가는 “청약일자”로 조회
  • 누군가는 “보험개시일자”로 조회
  • 누군가는 “보험종료일자”로 조회
  • 누군가는 “데이터생성일시”로 조회
✔ 결론

➡️ 서로 완전 중복은 아니지만
➡️ 선두 컬럼(계약ID)은 같아서 “불완전 중복”이라고 부름
➡️ 업무 상황을 보고 필요한 것만 남기고 버려야 함

🔍 3. 불완전 중복을 판단하는 기준

✔ 기준 1: 실제로 사용되는 쿼리 조건

  • 예: 계약ID + 보험개시일자 로 조회가 아주 많다
  • X02는 반드시 필요

✔ 기준 2: 쿼리 패턴 빈도

  • 예: 계약ID + 청약일자는 거의 안 쓰임
  • X01은 삭제 후보

✔ 기준 3: 뒤 컬럼의 선택도

  • 값이 매우 적은 컬럼이면 인덱스 가치 ↓
  • 값 분포가 넓고 WHERE 조건으로 자주 쓰이면 인덱스 가치 ↑

✔ 기준 4: 겹치는 정도

  • 선두 컬럼 같음 → 테이블 스캔 패턴 비슷
  • 하지만 뒤 컬럼이 다름 → 스캔 범위 달라짐

8️⃣ 인덱스 설계도 작성

📌 테이블의 전체 액세스 패턴을 한눈에 정리하는 문서

대표적으로 인덱스 설계도에 포함되는 항목

  • 테이블명
  • 가장 많이 쓰는 SQL 패턴
  • 각 조건의 엑세스 경로
  • 후보 인덱스
  • 최종 인덱스 구성
  • 풀스캔 발생 여부
  • BETWEEN, ORDER BY 여부

➡️ 이를 통해 인덱스를 구조적으로 관리

profile
Data가 좋은 Web 개발자

0개의 댓글