-
[📝 DB] DB 테이블의 인덱스의 기준스터디 노트 2025. 6. 27. 12:54
데이터베이스 테이블에 인덱스를 거는 것은 쿼리 성능을 최적화하는 데 매우 중요하지만, 무분별하게 인덱스를 생성하면 오히려 성능 저하를 초래할 수 있습니다. 인덱스는 검색 속도를 높여주지만, 데이터 삽입, 수정, 삭제 시 추가적인 작업이 발생하여 오버헤드를 유발하기 때문입니다.
다음은 DB 테이블에 인덱스를 걸 때 고려해야 할 핵심 기준들입니다.
1. 인덱스 설정의 핵심 기준 (4가지)
- 카디널리티 (Cardinality)가 높은 컬럼:
- 카디널리티: 특정 컬럼의 데이터 중복도를 나타내는 지표입니다. 값이 다양하고 중복이 적을수록 카디널리티가 높다고 말합니다.
- 기준: 카디널리티가 높을수록 (즉, 고유한 값이 많을수록) 인덱스를 설정하기에 좋습니다. 주민등록번호, 계좌번호, 이메일 주소, 사용자 ID와 같이 거의 중복되지 않는 컬럼이 대표적입니다. 인덱스를 통해 불필요한 데이터를 대부분 걸러낼 수 있어 검색 효율이 매우 높아집니다.
- 예시: 성별(남자/여자)과 같이 카디널리티가 낮은 컬럼은 인덱스 효과가 미미합니다.
- 선택도 (Selectivity)가 낮은 컬럼:
- 선택도: 특정 컬럼의 값이 전체 데이터에서 얼마나 잘 선택되는지를 나타내는 지표입니다. 선택도가 낮다는 것은 특정 값으로 검색했을 때 조회되는 레코드 수가 적다는 의미입니다.
- 기준: 선택도가 낮을수록 (일반적으로 5~10% 이하가 적당하다고 알려져 있습니다) 인덱스 설정에 좋습니다. 즉, 인덱스를 통해 소수의 레코드만 효율적으로 찾아낼 수 있을 때 인덱스의 가치가 높아집니다.
- 계산: (컬럼의 특정 값의 ROW 수 / 테이블의 총 ROW 수) * 100
- 활용도 (Usage Frequency)가 높은 컬럼:
- 기준: WHERE 절, JOIN 조건, ORDER BY 절, GROUP BY 절에 자주 사용되는 컬럼에 인덱스를 설정합니다. 쿼리에서 해당 컬럼이 얼마나 자주 사용되는지가 중요합니다.
- 수정 빈도 (Update Frequency)가 낮은 컬럼:
- 기준: 인덱스는 데이터가 변경될 때마다 갱신되어야 합니다. 따라서 INSERT, UPDATE, DELETE 작업이 빈번하게 일어나는 컬럼에 인덱스를 설정하면 인덱스 유지 비용이 커져 오히려 성능 저하가 발생할 수 있습니다. 수정 빈도가 낮은 컬럼에 인덱스를 설정하는 것이 효율적입니다.
2. 인덱스 종류별 고려사항
- 클러스터형 인덱스 (Clustered Index):
- 특징: 테이블의 실제 데이터가 인덱스 키 순서로 물리적으로 정렬되어 저장됩니다. 테이블당 하나만 생성할 수 있습니다.
- 기준: 기본 키(Primary Key)에 자동으로 생성되거나, 테이블에서 가장 자주 범위 검색(Range Scan)이 일어나는 컬럼에 설정하는 것이 좋습니다. 데이터의 물리적 정렬이 중요하므로, 데이터 삽입/삭제/수정이 빈번하면 오버헤드가 클 수 있습니다.
- 예시: 주문 테이블의 주문일자, 사용자 테이블의 사용자ID (PK가 아닐 경우)
- 비클러스터형 인덱스 (Non-Clustered Index / Secondary Index):
- 특징: 실제 데이터는 정렬되지 않고, 인덱스 페이지에 데이터의 물리적 위치(포인터 또는 클러스터형 인덱스 키)를 저장합니다. 테이블당 여러 개 생성 가능합니다.
- 기준: 클러스터형 인덱스 외에 WHERE 절, JOIN 조건, ORDER BY 절에 자주 사용되는 컬럼들에 설정합니다. 특정 값 검색(=, IN)에 효율적입니다.
3. 복합 인덱스 (Composite Index) 기준
두 개 이상의 컬럼을 묶어 하나의 인덱스로 만드는 것입니다.
- 컬럼 순서가 매우 중요: 복합 인덱스를 구성할 때 컬럼의 순서는 쿼리 성능에 지대한 영향을 미칩니다.
- 일반적인 원칙: 쿼리의 WHERE 절에서 = (동등 조건)으로 자주 사용되면서 카디널리티가 가장 높은 컬럼을 선행 컬럼(가장 왼쪽)으로 배치하고, 그 다음으로 자주 사용되는 컬럼들을 순서대로 배치하는 것이 좋습니다.
- 선행 컬럼 조건: 인덱스는 선행 컬럼을 기준으로 정렬되므로, 쿼리에서 선행 컬럼이 조건으로 사용되지 않으면 해당 인덱스를 효율적으로 활용하기 어렵습니다.
- 예시: WHERE (지역 = '서울') AND (나이 = 30) 이라는 쿼리가 자주 사용된다면, (지역, 나이) 순서로 인덱스를 거는 것보다 (나이, 지역) 순서가 더 효율적일 수 있습니다 (나이의 카디널리티가 더 높을 경우).
- 커버링 인덱스 (Covering Index) 고려: 쿼리에서 필요한 모든 컬럼이 인덱스 내에 포함되어 있어, 실제 테이블에 접근하지 않고 인덱스만으로 모든 데이터를 조회할 수 있는 경우를 말합니다. 매우 빠른 성능을 기대할 수 있습니다.
4. 인덱스 생성 시 주의사항
- 너무 많은 인덱스 생성 금지:
- 인덱스는 추가적인 저장 공간을 필요로 합니다.
- 데이터 삽입, 수정, 삭제 시 인덱스도 함께 갱신해야 하므로 쓰기 성능이 저하됩니다.
- 옵티마이저가 적절한 인덱스를 선택하는 데 더 많은 시간을 소모할 수 있습니다.
- 일반적으로 테이블당 3~5개 정도가 적당하다고 알려져 있지만, 테이블의 크기나 쿼리 패턴에 따라 달라질 수 있습니다.
- 작은 테이블에는 인덱스 불필요: 데이터 양이 적은 테이블은 풀 테이블 스캔(Full Table Scan)이 인덱스 스캔보다 빠를 수 있습니다. 인덱스를 탐색하고 실제 데이터에 접근하는 오버헤드가 더 크기 때문입니다.
- NULL 값이 많은 컬럼: NULL 값이 많은 컬럼은 인덱스 효율이 떨어질 수 있습니다 (DBMS에 따라 처리 방식이 다름).
- 인덱스 컬럼 가공 피하기: WHERE 절에서 인덱스 컬럼에 함수(SUBSTR(), UPPER(), YEAR())를 사용하거나, 묵시적 형 변환이 일어나거나, 부정형 비교(!=, <>), LIKE '%검색어' 와 같이 와일드카드가 앞에 오는 경우 인덱스를 사용하지 못하고 풀 테이블 스캔으로 전환될 수 있습니다.
- OR 조건 사용 주의: WHERE 절에 OR 조건을 사용하면 인덱스를 사용하지 못하고 풀 테이블 스캔으로 이어질 확률이 높습니다. 가능한 UNION ALL 또는 IN 조건으로 대체하는 것을 고려합니다.
마치며
인덱스는 DB 성능 튜닝의 핵심이지만, 신중하게 접근해야 합니다.
- 자주 쿼리되는 컬럼 (특히 WHERE, JOIN, ORDER BY 절).
- 카디널리티가 높고 선택도가 낮은 컬럼.
- 데이터 변경이 적은 컬럼.
- 테이블당 적절한 개수(3~5개)를 유지하고, 복합 인덱스 시 컬럼 순서를 고려합니다.
- 인덱스를 효율적으로 사용하지 못하는 WHERE 절 패턴을 피합니다.
가장 좋은 방법은 실제 운영 환경과 유사한 조건에서 쿼리를 실행해보고, EXPLAIN (SQL Server의 경우 SHOW PLAN 또는 EXECUTION PLAN)과 같은 도구를 사용하여 인덱스가 제대로 사용되는지, 성능상 병목이 어디인지 실행 계획을 확인하면서 인덱스를 추가하고 수정하는 것입니다.
'스터디 노트' 카테고리의 다른 글
[📝 Front] let과 const 그리고..var (0) 2025.06.27 [📝 DB] 외래 키(FK) 설정의 주요 이유 (0) 2025.06.27 [📝 JPA] 연관관계의 주인과 매핑관련 스터디 (0) 2025.06.26 📝 [JPA] @EntityGraph에 대하여.. (1) 2025.06.25 [Docker + Spring Boot] Spring boot jar 배포 시 도커 컨테이너 내 파일 위치 확인(app.jar) (0) 2025.03.25 - 카디널리티 (Cardinality)가 높은 컬럼: