EXPLAIN SELECT * FROM orders
WHERE user_id = 123
ORDER BY created_at DESC;
EXPLAIN 결과 읽기 (MySQL)
+----+------+-------+------+------+----------+
| id | type | table | key | rows | Extra |
+----+------+-------+------+------+----------+
| 1 | ref | orders| idx | 15 | Using .. |
+----+------+-------+------+------+----------+
type 컬럼 (접근 방식, 성능순)
type
의미
성능
const
PK/유니크 1건
최고
ref
인덱스 동등 조건
좋음
range
인덱스 범위 스캔
보통
index
인덱스 풀 스캔
나쁨
ALL
테이블 풀 스캔
최악
Extra 컬럼의 핵심 키워드
Using index → 커버링 인덱스 (좋음!)
Using where → WHERE 필터링 (보통)
Using filesort → 정렬 추가 수행 (주의)
Using temporary → 임시 테이블 생성 (주의)
Using index condition → 인덱스 컨디션 푸시다운
실무 튜닝 예시
-- 느린 쿼리
EXPLAIN SELECT * FROM orders
WHERE status = 'pending'
ORDER BY created_at;
-- type: ALL, Extra: Using filesort ← 풀스캔 + 정렬!
-- 인덱스 추가 후
CREATE INDEX idx_status_date
ON orders (status, created_at);
EXPLAIN SELECT * FROM orders
WHERE status = 'pending'
ORDER BY created_at;
-- type: ref, Extra: Using index condition ← 개선!
PostgreSQL EXPLAIN 차이
-- PostgreSQL은 비용 정보 제공
EXPLAIN ANALYZE SELECT ...
-- 결과 예시
Seq Scan on orders
(cost=0.00..1234.00 rows=100 width=52)
(actual time=0.5..15.2 rows=98 loops=1)
항목
의미
cost
예상 비용 (상대값)
rows
예상 행 수
actual time
실제 실행 시간
ANALYZE
실제 실행하여 측정
면접에서 이렇게 나옵니다
Q.EXPLAIN 결과에서 type이 ALL이면 어떤 의미이고, 어떻게 개선하나요?
풀 테이블 스캔입니다. 인덱스를 쓰지 못하고 모든 행을 읽습니다.
원인부터 확인합니다.
원인
조치
조건 컬럼에 인덱스가 없다
인덱스를 만든다
컬럼에 함수를 씌웠다
범위 조건으로 다시 쓴다
타입이 다르다
값의 타입을 맞춘다
복합 인덱스의 선행 컬럼이 없다
순서를 바꾸거나 다른 인덱스를 만든다
조건이 대부분의 행에 해당한다
정상이다. 풀 스캔이 더 빠르다
마지막 경우가 중요합니다. 결과가 전체의 30%를 넘으면 옵티마이저가 일부러 풀 스캔을 고릅니다. 인덱스로 하나씩 찾아 테이블을 왕복하는 것보다 순차로 다 읽는 것이 빠르기 때문입니다.
흔한 실수: ALL 을 보면 무조건 인덱스를 추가하는 것. 작은 테이블이거나 대부분을 읽는 쿼리면 인덱스가 오히려 느립니다.
Q.Using filesort와 Using temporary는 각각 어떤 상황에서 발생하나요?
표시
언제
뜻
Using filesort
ORDER BY 를 인덱스로 해결하지 못할 때
결과를 따로 정렬한다
Using temporary
GROUP BY, DISTINCT, 일부 UNION
중간 결과를 임시 테이블에 담는다
이름이 오해를 부릅니다. filesort 는 반드시 파일을 쓰는 것이 아니라, 정렬 버퍼로 끝나면 메모리에서 처리합니다. 결과가 크면 디스크를 씁니다.
해결 방향입니다.
상황
조치
ORDER BY 컬럼이 인덱스에 없다
정렬 컬럼까지 포함한 복합 인덱스
WHERE 와 ORDER BY 컬럼이 다른 인덱스
하나의 복합 인덱스로 합친다
GROUP BY 가 인덱스 순서와 다르다
인덱스 순서를 맞춘다
정렬 대상이 너무 많다
먼저 걸러내거나 커서 페이지네이션으로 바꾼다
흔한 실수: 둘 다 무조건 나쁘다고 보는 것. 결과가 수십 행이면 정렬 비용이 미미합니다. 수십만 행을 정렬할 때 문제가 됩니다.
Q.느린 쿼리를 발견했을 때 어떤 순서로 분석하나요?
순서
하는 일
1
실제로 느린지 확인한다. 평균인지 특정 조건에서만인지
2
실행 계획을 본다. 스캔 방식, 읽은 행 수, 정렬과 임시 테이블
3
예상과 실제를 비교한다. 크게 다르면 통계가 오래된 것이다
4
인덱스로 풀리는지 본다. 없거나, 있는데 못 타는지
5
쿼리를 고친다. 함수 제거, 조인 순서, 불필요한 컬럼 제거
6
그래도 안 되면 구조를 본다. 파티셔닝, 캐시, 반정규화
3번이 자주 빠집니다. 옵티마이저가 예상한 행 수와 실제가 수백 배 다르면 잘못된 계획을 고르고, 원인은 통계가 낡은 것입니다. 통계 갱신만으로 해결되는 경우가 있습니다.
같은 쿼리라도 파라미터에 따라 계획이 달라질 수 있으므로, 문제가 된 실제 값으로 확인해야 합니다.
흔한 실수: 계획만 보고 실제 실행을 안 해보는 것. 예상 비용과 실제 소요는 다릅니다. 실측 옵션으로 실제 행 수와 시간을 함께 봐야 합니다.