나는 주로 아래와 같은 상황에서 사용한다.
EXPLAIN 키워드만 붙이면 된다!EXPLAIN SELECT * FROM recruitment r JOIN shelter s ON r.shelter_id = s.shelter_id ORDER BY r.created_at desc limit 0, 20;

SELECT 문이 포함된 복잡한 쿼리(예: 서브쿼리, 조인 등)에서 MySQL이 각 부분을 어떻게 처리하는지 분석할 때 중요select_type 값 | 설명 | 성능 |
|---|---|---|
| SIMPLE | 서브쿼리나 UNION이 없는 단순한 SELECT 문 | ✅ 빠름 |
| PRIMARY | 가장 바깥쪽 SELECT (즉, 최상위 쿼리) | ✅ 빠름 |
| SUBQUERY | SELECT 문이 서브쿼리로 실행되는 경우 | ⚠️ 성능 저하 가능 |
| DEPENDENT SUBQUERY | 상위 쿼리의 컬럼을 참조하는 서브쿼리 (WHERE 안에 존재) | ❌ 느림 |
| DERIVED | FROM 절에서 서브쿼리(SELECT FROM (SELECT ...))를 사용하는 경우 (파생 테이블) | ⚠️ 성능 저하 가능 |
| UNCACHEABLE SUBQUERY | 상수 값이 아닌 변수를 기반으로 실행되어 결과를 캐싱할 수 없는 서브쿼리 | ❌ 매우 느림 |
| UNION | UNION을 사용한 쿼리에서 두 번째 이후의 SELECT 문 | ✅ 괜찮음 |
| UNION RESULT | UNION의 최종 결과를 저장하는 임시 테이블 | ⚠️ 임시 테이블 생성 가능 |
| DEPENDENT UNION | UNION의 일부가 상위 쿼리에 의존하는 경우 | ❌ 느림 |
DEPENDENT SUBQUERY는 JOIN으로 변경 → 성능 개선됨.DERIVED 테이블이 크다면 TEMPORARY TABLE을 고려.UNION 대신 UNION ALL 사용 → 불필요한 중복 제거를 피할 수 있음.type 값 | 설명 | 성능 |
|---|---|---|
| system | 테이블이 한 행만 포함하고 있을 때 사용됨 (상수 테이블) | 🔥 가장 좋음 |
| const | 기본 키나 유니크 인덱스를 이용하여 단 하나의 행만 조회할 때 사용됨 | 🔥 매우 좋음 |
| eq_ref | 조인 시 PRIMARY KEY 또는 UNIQUE KEY를 기준으로 매칭되는 경우 | |
| (조인 수행을 위해 각 테이블에서 하나의 행만 읽혀지는 형태) | 🔥 좋음 | |
| ref | eq_ref보다 덜 엄격한 조건, 보통 보조 인덱스를 이용한 조회 | 👍 괜찮음 |
| fulltext | FULLTEXT 인덱스를 사용한 검색 | 👍 괜찮음 |
| ref_or_null | ref와 유사하지만 NULL 값을 포함하는 경우 | 😐 보통 |
| index_merge | 여러 개의 인덱스를 병합하여 검색 | 😐 보통 |
| unique_subquery | 서브쿼리에서 IN (SELECT PRIMARY KEY FROM ...) 형태로 실행되는 경우 | 😐 보통 |
| index_subquery | unique_subquery와 유사하지만 PRIMARY KEY가 아닌 보조 인덱스를 사용 | 😐 보통 |
| range | 특정 범위 검색 (예: BETWEEN, >, <, IN(...) 등) | 😐 보통 |
| index | 테이블의 모든 데이터를 인덱스를 통해 조회 (풀 인덱스 스캔) | 😢 느림 |
| ALL | 테이블의 모든 데이터를 조회 (풀 테이블 스캔) | ❌ 매우 느림 |
ALL이나 index가 나오면 인덱스 추가 고려range보다 ref가 더 효율적 → 가급적 인덱스 키를 조정하여 ref가 되도록 유도eq_ref나 const가 나오도록 조인 최적화