요약
- OR 연산은 인덱스의 연속 스캔(range scan)을 방해하여 비효율을 유발한다
- 특히 서로 다른 컬럼 간의 OR 조건이 문제가 된다
본문
핵심 원리
B-Tree 인덱스는 정렬된 구조로, 연속된 범위를 스캔하도록 설계되어 있다. OR 연산은 "A 아니면 B"를 찾아야 하므로 이 연속 스캔의 이점을 살리기 어렵다.
문제가 되는 케이스: 서로 다른 컬럼 간 OR
SELECT * FROM users
WHERE name = 'kim' OR email = 'test@example.com'
- 두 컬럼 모두 인덱스가 있어도 각각 스캔 후 합집합(Index Merge) 연산 필요
- Index Merge 비용이 높아 Full Scan이 더 나을 수 있음
괜찮은 케이스: 동일 컬럼의 OR
SELECT * FROM orders
WHERE status = 'PENDING' OR status = 'PROCESSING'
- 옵티마이저가
IN ('PENDING', 'PROCESSING')으로 자동 변환 - 인덱스 활용 가능
우회 방법
1. UNION ALL로 분리
SELECT * FROM users WHERE name = 'kim'
UNION ALL
SELECT * FROM users WHERE email = 'test@example.com' AND name != 'kim'
- 주의: UNION ALL은 중복 허용 → 조건이 상호 배타적인지 확인 필요
2. 동일 컬럼이면 IN 사용
WHERE status IN ('active', 'pending', 'review')
실무 팁
- EXPLAIN으로 실제 실행 계획 확인 필수
- OR 조건이 있는 느린 쿼리 발견 시 위 우회 방법 검토