인덱스가 안 타는 케이스

인덱스를 만들어도 쿼리 패턴에 따라 인덱스를 사용하지 않고 풀 스캔을 하는 경우가 있습니다. 실무에서 흔히 발생하는 함정들입니다.


1. 앞에 와일드카드 (LIKE '%...')

WHERE name LIKE '%철수'        -- X 인덱스 미사용
WHERE name LIKE '%철%'         -- X
WHERE name LIKE '철수%'        -- O 인덱스 사용

인덱스는 정렬된 트리이므로 앞부분이 고정되어야 탐색 가능합니다.


2. 인덱스 컬럼에 함수/연산 적용

-- 함수
WHERE UPPER(name) = 'CHEOLSU'  -- X
WHERE name = 'cheolsu'         -- O

-- 날짜 연산
WHERE YEAR(created_at) = 2026  -- X
WHERE created_at >= '2026-01-01' AND created_at < '2027-01-01'  -- O

-- 산술 연산
WHERE age + 1 = 30             -- X
WHERE age = 29                 -- O

인덱스에는 원본 값이 저장되어 있어서, 변환된 값으로는 탐색할 수 없습니다.


3. 묵시적 형변환

-- id 컬럼이 INT 타입일 때
WHERE id = '1'                 -- X 문자열 → 숫자 변환 발생
WHERE id = 1                   -- O

타입이 다르면 DB가 내부적으로 형변환을 적용 → 함수 적용과 동일하게 인덱스 무력화.


4. OR 조건

-- name, age 각각에만 인덱스가 있을 때
WHERE name = '철수' OR age = 28   -- X 보통 풀스캔

해결:


5. 부정 조건

WHERE name != '철수'           -- X
WHERE name NOT IN (...)        -- X
WHERE name NOT LIKE '철수%'    -- X

부정 조건은 거의 모든 행이 매칭되므로 인덱스를 타도 이득이 없어 옵티마이저가 풀스캔을 선택하는 경우가 많습니다.


6. 복합 인덱스의 선두 컬럼 누락

CREATE INDEX idx ON users(name, age);

WHERE age = 28                 -- X 선두 컬럼(name) 없음
WHERE name = '철수'            -- O
WHERE name = '철수' AND age = 28  -- O

복합 인덱스는 왼쪽부터 순서대로 사용해야 합니다.


7. 카디널리티가 너무 낮을 때

CREATE INDEX idx_gender ON users(gender);  -- 남/여 2개뿐
WHERE gender = '남'            -- 옵티마이저가 풀스캔 선택

값 종류가 적으면 인덱스를 타도 결과가 너무 많아 풀스캔이 더 빠릅니다.


확인 방법

EXPLAIN으로 실행 계획을 확인할 수 있습니다.

EXPLAIN SELECT * FROM users WHERE UPPER(name) = '철수';

CSLOG에서 보기