이름은 비슷하지만 완전히 다른 최적화 기법입니다:
둘 다 "건너뛴다"는 공통점이 있지만, 건너뛰는 대상과 목적이 전혀 다릅니다.
복합 인덱스의 제약
복합 인덱스 INDEX(A, B, C)는 왼쪽부터 순서대로 사용해야 합니다:
WHERE A=1 AND B=2 ✅ 인덱스 사용 가능WHERE B=2 AND C=3 ❌ A가 없어서 인덱스 효율 낮음이 제약을 완화하는 것이 인덱스 스킵 스캔입니다.
GROUP BY의 비용
GROUP BY는 보통 모든 레코드를 읽어 그룹핑하는데, 인덱스가 이미 정렬되어 있다면 각 그룹의 대표값만 읽을 수 있습니다. 이것이 루스 인덱스 스캔입니다.
핵심 차이점 비교
| 구분 | 인덱스 스킵 스캔 | 루스 인덱스 스캔 |
|---|---|---|
| 도입 버전 | MySQL 8.0.13+ | MySQL 5.0+ (오래됨) |
| 주요 용도 | WHERE 조건 처리 | GROUP BY 처리 |
| 해결 문제 | 인덱스 앞 컬럼 없는 쿼리 | 그룹별 MIN/MAX 구하기 |
| 건너뛰는 대상 | 앞 컬럼의 고유값들 | 같은 그룹의 레코드들 |
| EXPLAIN 표시 | Using index for skip scan | Using index for group-by |
| 사용 조건 | 앞 컬럼 카디널리티 낮음 | MIN/MAX만 사용, 왼쪽 접두사 |
인덱스 스킵 스캔 상세
복합 인덱스 INDEX(gender, birth_date)에서:
-- gender 조건 없이 birth_date만 검색
SELECT * FROM users WHERE birth_date = '1990-01-01';
-- 내부적으로 다음처럼 변환됨:
WHERE gender='M' AND birth_date='1990-01-01'
UNION ALL
WHERE gender='F' AND birth_date='1990-01-01'
gender의 고유값('M', 'F')을 자동으로 순회하면서 각각 인덱스 검색을 수행합니다.
루스 인덱스 스캔 상세
복합 인덱스 INDEX(category_id, price)에서:
-- 각 카테고리의 최소 가격 구하기
SELECT category_id, MIN(price)
FROM products
GROUP BY category_id;
인덱스가 이미 category_id로 정렬되어 있고, 같은 category_id 내에서 price가 정렬되어 있으므로, 각 카테고리의 첫 레코드만 읽으면 MIN 값을 알 수 있습니다.
언제 각각 사용되나?
스킵 스캔:
루스 스캔:
스킵 스캔은 앞 컬럼 값을 순회하고, 루스 스캔은 그룹 내 레코드를 건너뜁니다.