✅ Query Cost가 높아지는 조건과 성능 개선 포인트
✅ 1. 쿼리 비용(Query Cost)이란?
- MySQL 옵티마이저(optimizer)가 계산한 논리적 실행 비용
EXPLAIN
또는 EXPLAIN ANALYZE
에서 cost=0.15..23.80
이런 식으로 나타남
- 크다고 해서 항상 "나쁘다"는 뜻은 아님 → 상대적 판단 기준
- 주로 다음 요소가 반영됨:
- 디스크 I/O 비용 (풀 테이블 스캔, 정렬, 임시 테이블)
- 읽는 행 수
- 인덱스 사용 여부
- 조인 순서
- 반복 루프 횟수
✅ 2. 쿼리 비용이 높아지는 주요 조건 + 개선 방향
조건 |
성능 저하 원인 |
개선 포인트 |
1. type: ALL |
테이블 전체 스캔 (풀스캔) |
인덱스 추가, WHERE 조건 개선 |
2. key: NULL |
인덱스 미사용 |
적절한 인덱스 생성 |
3. WHERE 절에 함수 사용 |
인덱스 범위 못 잡음 |
WHERE DATE(col) → BETWEEN 사용 |
4. Using temporary |
임시 테이블 생성 (GROUP BY 등) |
GROUP BY 대상에 인덱스 포함 |
5. Using filesort |
정렬 성능 저하 (ORDER BY) |
정렬 대상 인덱스 생성 |
6. JOIN 순서 잘못됨 |
큰 테이블 먼저 조인 → I/O 증가 |
작은 테이블 먼저 조인 |
7. 하위 쿼리 중첩 |
반복 실행 (비효율) |
JOIN 또는 CTE로 구조 재설계 |
8. OR 조건 복수 컬럼 |
옵티마이저 인덱스 사용 못함 |
UNION으로 분리 |
9. LIMIT 없이 대량 조회 |
메모리 + 네트워크 부하 |
LIMIT + 페이지네이션 적용 |
10. 서브쿼리에서 인덱스 미사용 |
서브쿼리 내부 풀스캔 발생 |
인덱스 조정 + EXISTS로 변경 고려 |
✅ 3. 성능 최적화를 위한 중점 개선 항목
🔸 1) 인덱스가 제대로 활용되는지 확인
EXPLAIN
의 key
가 NULL
이면 성능 병목
- WHERE, JOIN, ORDER BY, GROUP BY에 쓰이는 컬럼에 인덱스 설정
- 복합 인덱스 고려: 자주 함께 쓰이는 컬럼 순서대로
✅ 인덱스 예:
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
🔸 2) WHERE
조건에 함수나 계산 피하기
- ❌
WHERE YEAR(created_at) = 2023
- ✅
WHERE created_at BETWEEN '2023-01-01' AND '2023-12-31'
👉 함수 사용 시 인덱스가 무력화됨
🔸 3) ORDER BY
/ GROUP BY
최적화
EXPLAIN
의 Extra
에 Using filesort
, Using temporary
나오면 정렬/집계 비용 ↑
- 인덱스가 ORDER/GROUP 대상 컬럼 순서와 동일해야 함
-- 개선 전: 정렬 시 filesort 발생
SELECT * FROM posts ORDER BY created_at DESC;
-- 개선 후: 인덱스 생성
CREATE INDEX idx_posts_created ON posts(created_at DESC);
🔸 4) JOIN 순서, 방식 확인
EXPLAIN
에서 큰 테이블부터 조인하거나, type: ALL
이면 위험
- 작은 테이블 먼저 조인되도록 쿼리 구조/인덱스를 조정
-- 예: 작은 테이블 먼저 필터링
SELECT * FROM small_table s
JOIN big_table b ON s.id = b.s_id
WHERE s.status = 'active';
🔸 5) 서브쿼리 vs JOIN vs CTE 비교
- 서브쿼리는 행마다 반복 실행될 수 있어 비용 증가
- 가능하면 JOIN + GROUP BY로 변경
- MySQL 8 이상이면 CTE(WITH절)로 리팩토링 고려
✅ 4. 실무 기준 성능 분석 흐름
- ✅
EXPLAIN
으로 실행 계획 확인
- ❗
type = ALL
, key = NULL
, Extra: Using filesort/temporary
있는지 확인
- 🔍 스캔 행 수(
rows
)가 수십만 이상인지 확인
- ✅
EXPLAIN ANALYZE
로 실제 수행 시간 측정
- ⚙️ 인덱스 최적화, 조인 순서 재구성
- 🚀 쿼리 리팩토링 후 다시
EXPLAIN
비교
✅ 예시: BEFORE vs AFTER
❌ BEFORE (문제 있음)
EXPLAIN SELECT * FROM orders WHERE LEFT(order_date, 7) = '2024-03';
-- type: ALL, key: NULL, rows: 1,000,000
✅ AFTER (개선)
SELECT * FROM orders
WHERE order_date BETWEEN '2024-03-01' AND '2024-03-31';
-- type: range, key: idx_order_date, rows: 12,000
✅ 정리: 성능을 위해 꼭 봐야 할 항목 5선
항목 |
중점 체크 |
type |
ALL → ref , range 이상으로 개선 |
key |
NULL이면 인덱스 미사용, 인덱스 설계 필요 |
rows |
수백만 이상이면 개선 필요 |
Extra |
Using filesort / Using temporary → 정렬/임시 테이블 사용중 |
EXPLAIN ANALYZE 의 actual time |
실제 응답 시간 기준으로 체감 성능 판단 |
댓글