반응형
인덱스를 걸었는데도 쿼리가 느릴 때가 있다. 실제로 많은 개발자가 인덱스를 적용했음에도 성능이 개선되지 않는 현상을 경험한다. 이런 경우에는 EXPLAIN을 통해 실행계획을 분석하고 인덱스가 실제로 사용되는지, 비효율적인 접근이 있는지를 체크해야 한다.
🔍 인덱스를 걸었는데 왜 느릴까?
인덱스는 자동으로 성능을 올려주지 않는다. 다음과 같은 이유로 인덱스가 무시되거나 비효율적으로 사용될 수 있다.
1. 함수 또는 연산 사용
-- 잘못된 예: 인덱스를 타지 않는다
SELECT * FROM user WHERE YEAR(created_at) = 2024;
2. LIKE 앞에 와일드카드 사용
-- %가 앞에 있으면 인덱스 무시
SELECT * FROM product WHERE name LIKE '%신발';
3. OR 조건 다중 사용
-- OR은 인덱스를 무시하게 할 가능성이 크다
SELECT * FROM board WHERE writer = 'kim' OR subject = '공지';
4. 통계적으로 효율이 없을 때
-- 인덱스가 있어도 대부분의 row를 읽는다면 풀스캔(FULL SCAN) 발생
SELECT * FROM users WHERE gender = 'M';
반응형
🧪 EXPLAIN으로 실행계획 분석하기
예제 쿼리
EXPLAIN SELECT * FROM orders WHERE status = 'SHIPPED';
주요 컬럼 분석
- type: ALL, index, range, ref, eq_ref 등 → ALL은 풀스캔이라 경고
- key: 사용된 인덱스 이름
- rows: 몇 건의 레코드를 탐색하는지 예상
- Extra: Using where / Using index / Using temporary 등 힌트 제공
분석 포인트
항목 | 설명 | 예시 |
type = ALL | 전체 테이블 탐색(비효율적) | ❌ 성능 저하 |
key = NULL | 인덱스 사용 안 함 | ❌ 원인 분석 필요 |
rows = 100000 | 많은 행을 탐색함 | ❗ 필터 조건이 효율적이지 않음 |
Extra = Using temporary | 임시 테이블 사용 | ❗ 정렬, 그룹핑이 느릴 수 있음 |
반응형
⚠️ 잘못된 인덱스 사용 예시
-- 인덱스는 있지만, 정렬 때문에 임시 테이블과 filesort 발생
EXPLAIN SELECT * FROM orders ORDER BY created_at DESC LIMIT 10;
- Extra에 Using temporary; Using filesort가 나타난다.
- 해결법: created_at에 인덱스를 생성하거나 Covering Index 구성
CREATE INDEX idx_orders_created_at ON orders(created_at DESC);
🛠️ 해결 방법 정리
문제 유형 | 해결 방안 |
함수 사용 | 조건에서 함수 제거 |
OR 조건 | 쿼리 분리 후 UNION |
와일드카드 | 전체 검색 필요시 FULLTEXT 인덱스 고려 |
인덱스 미사용 | 컬럼 순서, 조건, 통계적 효율 점검 |
정렬/임시테이블 | ORDER BY 포함 인덱스 구성 |
🧠 실전 팁: 쿼리 리팩토링으로 속도 개선
쿼리가 느릴 땐 단순히 인덱스를 추가하기보다 EXPLAIN 결과를 기반으로 리팩토링하는 것이 핵심이다.
불필요한 조건 제거, 인덱스 커버링, 조건 최적화 등을 통해 수백 배의 성능 향상도 가능하다.
📎 공식 문서
MySQL 공식 EXPLAIN 문서:
https://dev.mysql.com/doc/refman/8.0/en/explain-output.html
반응형
'DB' 카테고리의 다른 글
[MySQL] 서브쿼리 vs JOIN 성능 비교와 실행계획으로 분석하기 (1) | 2025.07.04 |
---|---|
[MySQL] JOIN이 느릴 때 실행계획으로 튜닝하는 방법 (0) | 2025.07.04 |
[MySQL] 실무 예제로 배우는 느린 쿼리 튜닝 실습 (EXPLAIN + INDEX 활용) (0) | 2025.07.04 |
[MySQL] 효율적인 쿼리 작성법: 실행계획 튜닝을 고려한 SQL 설계 전략 🏗️ (1) | 2025.07.04 |
[MySQL] Extra 컬럼에 자주 뜨는 문구 해석법 (Using temporary 등) 🧐 (1) | 2025.07.04 |
[MySQL] key vs possible_keys vs rows 차이점 제대로 알기 🔍 (0) | 2025.07.04 |
[MySQL] EXPLAIN 컬럼 완전정복: type, key, rows, Extra 해석법 🔬 (0) | 2025.07.04 |
[MySQL] EXPLAIN이란? 실행계획을 확인하는 이유와 기본 구조 정리 🔍 (0) | 2025.07.04 |