본문 바로가기
카테고리 없음

쿼리 성능 최적화 기본기: 인덱스, 실행 계획(EXPLAIN) 분석

by business27 2025. 8. 15.

대용량 데이터를 다루는 서비스에서 SQL 쿼리 성능은 곧 서비스 속도와 직결됩니다. 같은 데이터를 가져오는 쿼리라도 몇 초 걸리느냐, 몇 밀리초 걸리느냐의 차이는 사용자 경험을 크게 바꿉니다. 이번 글에서는 쿼리 최적화의 기초 중 기초인 인덱스와 실행 계획(EXPLAIN)을 중심으로, 실무에서 꼭 알아야 할 최적화 원리를 정리하겠습니다.

 

 

 

 

쿼리 성능 최적화 기본기: 인덱스, 실행 계획(EXPLAIN) 분석

 

 

 

 

인덱스(Index)란?

인덱스는 데이터베이스의 책갈피 역할을 합니다. 전체 데이터를 처음부터 끝까지 읽는 Full Table Scan 대신, 인덱스를 통해 원하는 데이터가 있는 위치를 빠르게 찾아갈 수 있습니다.

 

 

📌 인덱스 기본 원리

* DB는 보통 B-Tree 구조로 인덱스를 저장

* 루트 노드 → 브랜치 노드 → 리프 노드로 내려가며 값을 탐색

* 리프 노드에 해당 레코드의 실제 위치(ROWID 등) 저장

 

 

📌 인덱스 장점

* 조회 속도 향상 (특히 WHERE, JOIN, ORDER BY, GROUP BY에 사용 시)

* 대량 데이터에서도 일정한 검색 속도 유지

 

 

📌 인덱스 단점

* INSERT, UPDATE, DELETE 시 인덱스 갱신 오버헤드 발생

* 디스크 공간 사용량 증가

* 너무 많은 인덱스 → 쿼리 성능 저하

 

 

 

 

인덱스 종류

1) 기본 인덱스(Primary Key)

* 고유한 값에 자동 생성

* 각 테이블당 하나만 존재

 

2) 고유 인덱스(Unique Index)

* 중복 허용 안 함

* 이메일, 주민번호 같은 컬럼에 주로 사용

 

3) 비고유 인덱스(Non-Unique Index)

* 중복 가능

* 조회 조건에 자주 쓰이는 컬럼에 사용

 

4) 복합 인덱스(Composite Index)

* 여러 컬럼을 묶어서 생성

* 인덱스 순서가 중요 (선행 컬럼 기준 검색 시만 효율적)

 

5) 커버링 인덱스(Covering Index)

* 쿼리에 필요한 모든 컬럼이 인덱스에 포함되어 데이터 페이지 접근 없이 인덱스만으로 처리 가능

 

 

인덱스 생성 예제

-- 단일 컬럼 인덱스
CREATE INDEX idx_users_email ON users(email);

-- 복합 인덱스 (name, age 순서)
CREATE INDEX idx_users_name_age ON users(name, age);

 

💡 복합 인덱스 주의점

* ( name, age) 인덱스 → name으로 검색 O, age 단독 검색 X

* 선행 컬럼을 WHERE 조건에 포함시키는 것이 중요

 

 

인덱스 사용 여부 확인하기

아무리 인덱스를 걸어도 쿼리가 그 인덱스를 사용하지 않을 수 있습니다. 이럴 때 쓰는 도구가 바로 EXPLAIN입니다.

 

 

 

실행 계획(EXPLAIN) 분석

MySQL에서 EXPLAIN은 쿼리 실행 계획을 보여주는 명령어입니다.

EXPLAIN
SELECT name, age
FROM users
WHERE email = 'test@example.com';


📌 주요 컬럼 설명

[컬럼 설명]

id 쿼리 실행 순서
select_type SELECT 유형 (SIMPLE, SUBQUERY, DERIVED 등)
table 참조하는 테이블명
type 접근 방식 (ALL, index, range, ref, eq_ref, const 등)
possible_keys 사용할 수 있는 인덱스 후보
key 실제 사용된 인덱스
rows 예측 읽기 건수
Extra 추가 정보 (Using index, Using filesort 등)

 

 

📌 type(접근 방식) 성능 순서

const > eq_ref > ref > range > index > ALL

 

* ALL: 전체 테이블 스캔 (가장 느림)

* range: 범위 검색 (BETWEEN, >, < 등)

* ref: 동등 비교로 인덱스 참조

* const: PK나 Unique Key로 단일 행 조회

 

 

📌 Extra 컬럼 해석

* Using index: 커버링 인덱스 사용 (성능 좋음)

* Using where: WHERE 필터링 수행

* Using filesort: 별도 정렬 발생 (가능하면 피해야 함)

* Using temporary: 임시 테이블 생성 (GROUP BY, DISTINCT에서 자주 발생)

 

 

 

인덱스 + EXPLAIN 최적화 예시

📌 최적화 전

EXPLAIN
SELECT name, age
FROM users
WHERE YEAR(created_at) = 2024;


* 문제점: YEAR(created_at) 함수 사용 → 인덱스 적용 불가

* type: ALL (풀스캔)

* rows: 1,000,000

 

 

📌 최적화 후

EXPLAIN
SELECT name, age
FROM users
WHERE created_at >= '2024-01-01'
AND created_at < '2025-01-01';


* 결과: range 접근 방식

* 인덱스 사용 (idx_created_at)

* rows: 10,000 (훨씬 적음)

 

💡 함수나 연산이 컬럼에 직접 적용되면 인덱스 무력화
→ 조건식을 변형해서 인덱스를 활용해야 함

 

 

 

실무 최적화 팁

1. WHERE 절 컬럼 순서와 인덱스 순서 맞추기

2. SELECT * 지양 → 필요한 컬럼만 조회 (커버링 인덱스 유도)

3. 함수/연산 피하기 → 인덱스 활용 가능 형태로 변경

4. LIMIT 최적화 → 정렬 + 인덱스 활용

5. 통계 갱신 (ANALYZE TABLE) → 옵티마이저가 최신 데이터 분포를 알아야 최적화 가능

 

 

마무리

인덱스와 실행 계획(EXPLAIN)은 SQL 최적화의 출발점이자 필수 도구입니다.

* 인덱스는 검색 속도를 빠르게

* EXPLAIN은 쿼리의 병목 구간을 시각화

* 인덱스 설계 → 실행 계획 확인 → 조건식 최적화 → 재검증

이 사이클을 반복하면 대부분의 쿼리 성능 문제를 해결할 수 있습니다.