[DB] 왜 함수나 연산을 쓰면 인덱스를 못 탈까?

HenryHong·2026년 2월 11일

DB

목록 보기
17/18

인덱스는 ‘사전(Dictionary)’이다

DB는 인덱스를 “미리 정렬된 사전(dictionary)”처럼 관리합니다.
예를 들어 salary 컬럼에 인덱스가 걸려 있다면, DB 내부에는 이런 식의 정렬 구조가 존재하죠.

... 280 | 290 | 300 | 310 | 320 | ...

즉, “300”이라는 값을 찾을 때 DB는 사전에서 단어 찾듯 정확한 위치로 점프할 수 있습니다.
그런데 이때 단어를 꼬아버리면, DB는 사전을 더 이상 이용할 수 없게 됩니다.


1. 나쁜 예시 – 연산을 적용한 쿼리

SELECT * FROM employee
WHERE salary * 12 = 3600;

이렇게 작성하면 DB는 다음과 같이 생각합니다:

"salary 컬럼 값이 300인 데이터를 찾고 싶은데,
인덱스에 있는 값에 ‘* 12’를 해야 하네?
그러면 인덱스 순서를 유지할 수 없으니까 다 뒤져봐야겠다."

결과적으로 Full Table Scan이 발생합니다.
DB는 모든 행의 salary 값을 꺼내 하나하나 계산한 뒤 3600이 나오는지 비교해야 하기 때문입니다.


2. 좋은 예시 – 상수 쪽을 계산하기

SELECT * FROM employee
WHERE salary = 3600 / 12;

여기서 3600 / 12는 계산 결과가 300이므로, 옵티마이저는 이렇게 판단합니다:

“salary 컬럼이 300인 값을 인덱스에서 바로 찾아볼게요!”

이 경우엔 salary 컬럼의 원본 인덱스를 그대로 활용할 수 있어서
Index Range Scan으로 빠르게 처리됩니다.


3. 날짜 함수가 문제를 일으키는 경우

날짜 컬럼에 함수 적용하는 경우도 마찬가지입니다. 실무에서 정말 많이 보이는 예죠.

--  인덱스 안 탐
SELECT * FROM orders
WHERE DATE_FORMAT(reg_date, '%Y-%m-%d') = '2026-02-11';

reg_date에 함수가 적용되면서 컬럼이 “가공된 값”으로 바뀌기 때문에
DB는 인덱스 정렬 순서를 활용할 수 없습니다.

이럴 땐 이렇게 수정해야 합니다 👇

--  인덱스 잘 탐
SELECT * FROM orders
WHERE reg_date >= '2026-02-11 00:00:00'
  AND reg_date <= '2026-02-11 23:59:59';

컬럼을 그대로 두고 비교 구문(right-hand side) 에서만 연산·가공을 수행해야 합니다.
이렇게 하면 인덱스가 정렬된 상태 그대로 탐색 대상 범위를 좁힐 수 있죠.


핵심 개념 요약

상황인덱스 사용 여부이유
salary * 12 = 3600컬럼에 연산 적용
salary = 3600 / 12상수 쪽만 계산
DATE_FORMAT(reg_date)컬럼에 함수 적용
reg_date BETWEEN ...컬럼 원본 그대로 사용

💡 정리하자면:

인덱스는 “가공되지 않은 원본 데이터”의 정렬 지도다.
WHERE 절에서 컬럼은 절대 가공하지 말고,
계산이 필요하다면 상수(혹은 우변) 쪽으로 넘겨라.


실무 팁

  • 쿼리를 작성할 때 항상 WHERE 컬럼 좌측을 건드리고 있지는 않은가? 점검하자.
  • EXPLAIN으로 실행 계획을 확인해보면 type=ALL(Full Table Scan)이 뜬다면 대부분 이런 문제다.
  • ORM(JPA 등)을 사용할 땐 function() 호출이나 계산 로직을 WHERE 절에 넣기 전에 반드시 주의할 것.
profile
주니어 백엔드 개발자

0개의 댓글