🎯 학습 목표
- 인덱스가 무력화되는 대표 패턴을 식별하고 고친다.
- 결합 인덱스에서 컬럼 순서가 왜 중요한지 이해한다.
- SARGable한(인덱스를 탈 수 있는) 조건으로 SQL을 작성한다.
📖 핵심 규칙: “인덱스 컬럼을 가공하면 인덱스를 못 탄다”
인덱스는 컬럼 값 그대로를 정렬해 둡니다. WHERE 절에서 그 컬럼을 함수로 감싸거나 연산하면, 인덱스에 저장된 “원래 값”과 매칭할 수 없어 옵티마이저가 인덱스를 포기하고 전체 스캔으로 빠집니다. 이것이 실무에서 인덱스가 안 타는 1순위 원인입니다.
💻 실수 1) 컬럼을 함수/연산으로 가공
-- ❌ 인덱스(hire_date) 무력화: 컬럼을 함수로 감쌌다
SELECT * FROM emp WHERE TO_CHAR(hire_date,'YYYY') = '2024';
-- ✅ 컬럼은 그대로 두고, 상수 쪽을 가공 (범위 조건으로 변환)
SELECT * FROM emp
WHERE hire_date >= DATE '2024-01-01'
AND hire_date < DATE '2025-01-01';
-- ❌ 컬럼에 연산
SELECT * FROM orders WHERE price * 1.1 > 11000;
-- ✅ 상수 쪽으로 이항
SELECT * FROM orders WHERE price > 11000 / 1.1;
💻 실수 2) 암묵적 형변환(Implicit Conversion)
-- phone 컬럼이 VARCHAR2인데 숫자로 비교하면 오라클이 자동 형변환
-- ❌ 사실상 TO_NUMBER(phone) = ... 가 되어 인덱스 무력화
SELECT * FROM customer WHERE phone = 1055550000;
-- ✅ 타입을 맞춰 문자열로 비교
SELECT * FROM customer WHERE phone = '1055550000';
형변환은 눈에 안 보여 더 위험합니다. 컬럼과 비교 상수의 데이터 타입을 항상 일치시키세요.
💻 실수 3) 선두 와일드카드 LIKE / NULL 비교
-- ❌ 앞이 %면 정렬된 인덱스를 활용 못 함 → 전체 스캔
SELECT * FROM product WHERE name LIKE '%스피커%';
-- ✅ 앞부분이 고정이면 인덱스 범위 검색 가능
SELECT * FROM product WHERE name LIKE '무선%';
-- (앞 % 검색이 꼭 필요하면 Oracle Text 등 별도 기능 고려)
-- ❌ 일반 B-Tree 인덱스는 NULL을 따로 저장하지 않아 IS NULL 검색에 안 쓰임
SELECT * FROM emp WHERE mgr IS NULL; -- 보통 Full Scan
📖 결합 인덱스(복합 인덱스)와 컬럼 순서
여러 컬럼을 묶은 결합 인덱스는 (A, B)로 만들면 “A로 먼저 정렬, 같은 A 안에서 B로 정렬”됩니다. 마치 전화번호부가 (성, 이름) 순인 것과 같습니다. 그래서:
CREATE INDEX ix ON emp(deptno, ename); -- (deptno, ename) 순
WHERE deptno = 10 AND ename = 'KIM' → ✅ 인덱스 최적 활용 (선두 deptno 사용)
WHERE deptno = 10 → ✅ 선두 컬럼 사용 → 잘 탐
WHERE ename = 'KIM' → ❌ 선두(deptno) 조건이 없어 비효율
(성을 모르고 이름만으로 전화번호부 찾기)
규칙: 결합 인덱스는 선두 컬럼이 WHERE 조건에 있어야 제대로 탄다. 그리고 등호(=)로 자주 쓰는 컬럼을 앞에, 범위(>, BETWEEN)로 쓰는 컬럼을 뒤에 두는 것이 일반적으로 유리합니다(범위 조건 뒤의 컬럼은 인덱스 정렬이 흐트러져 활용도가 떨어지기 때문).
⚠️ 주의사항
- “함수를 꼭 써야 한다”면 함수 기반 인덱스(Function-Based Index)를 만들 수 있습니다:
CREATE INDEX ix ON emp(TO_CHAR(hire_date,'YYYY'));— 단, 인덱스가 늘어나는 비용을 감안하세요. - OR 조건, 부정 조건(
!=,NOT IN)도 인덱스 활용이 어려운 대표 패턴입니다. 가능하면 UNION ALL이나 IN으로 바꿀 수 있는지 검토하세요.
💡 팁
- 실행계획에서
TABLE ACCESS FULL이 떴다면, 먼저 “WHERE 절에서 인덱스 컬럼을 가공하지 않았나?”부터 점검하세요. 십중팔구 여기서 걸립니다. - 결합 인덱스 설계 전에 “이 테이블에서 가장 자주 쓰는 WHERE 조합이 무엇인가”를 먼저 조사하세요. 순서가 곧 성능입니다.