인덱스는 테이블의 데이터를 더 빠르게 찾기 위해 특정 컬럼의 값과 행의 위치 정보를 별도의 자료구조로 저장한 것입니다. MySQL의 일반적인 인덱스는 B-Tree 계열로 구성되어 전체 테이블을 순차 탐색하지 않고도 값이나 범위를 찾을 수 있습니다.
인덱스는 다음과 같은 경우에 효과적입니다.
- 큰 테이블에서 일부 행만 찾는 선택도 높은
WHERE조건 - 조인에 자주 사용하는 외래 키나 연결 컬럼
- 인덱스 순서를 활용할 수 있는
ORDER BY,GROUP BY, 범위 조회 - 중복을 허용하지 않아야 하는
PRIMARY KEY,UNIQUE제약
반면 다음과 같은 경우에는 효과가 작거나 비용이 더 클 수 있습니다.
- 행 수가 적어 전체 스캔이 더 저렴한 테이블
- 대부분의 행을 조회하는 쿼리나 단독으로 사용했을 때 선택도가 매우 낮은 컬럼
- INSERT, UPDATE, DELETE가 매우 빈번한 테이블에 과도하게 많은 인덱스를 두는 경우
- 크기가 큰 문자열을 그대로 포함하거나 실제 쿼리에서 거의 사용하지 않는 인덱스
인덱스는 읽기 속도를 공짜로 높이는 기능이 아닙니다. 별도의 저장 공간을 사용하고 데이터 변경 시 인덱스도 함께 갱신해야 합니다. 따라서 예상만으로 추가하기보다 실제 쿼리와 데이터 분포를 기준으로 실행 계획과 성능을 측정해야 합니다.
사용자가 별도의 인덱스를 직접 명시하지 않아도 조건에 만족한다면 인덱스를 통해 데이터를 조회한다. 이는 옵티마이저로 인해 인덱스가 선택되기 때문이다.
인덱스가 많으면 쓰기 성능이 느려지는 이유는 무엇인가요?
행을 추가·수정·삭제할 때 관련된 모든 인덱스의 엔트리도 변경해야 하기 때문입니다. B-Tree 페이지 분할이나 추가 I/O가 발생할 수 있고, 인덱스가 차지하는 메모리와 디스크 공간도 커집니다.
인덱스 컬럼에 함수를 사용하면 왜 인덱스를 사용하지 못할 수 있나요?
WHERE YEAR(created_at) = 2026처럼 저장된 인덱스 값이 아니라 함수 계산 결과를 비교하면 일반 인덱스의 정렬된 값을 그대로 탐색하기 어렵습니다. 가능하면 범위 조건으로 바꾸거나 DBMS가 지원하는 함수 기반 인덱스를 검토하고 실행 계획으로 확인해야 합니다.
JPA 엔티티에
@Index를 선언하면 쿼리가 자동으로 최적화되나요?아닙니다.
@Index는 스키마 생성 시 인덱스 DDL을 표현하는 메타데이터일 뿐, 실행되는 JPQL이나 SQL이 해당 인덱스를 반드시 사용하게 하지는 않습니다. Hibernate가 생성한 실제 SQL과 데이터 분포를 기준으로EXPLAIN을 확인해야 합니다.