핵심 답변
스토리지 엔진(InnoDB)은 인덱스를 사용한 조건만 처리하고, 함수/연산/서브쿼리 등 복잡한 조건은 MySQL 서버 레이어에서 추가로 필터링합니다.

MySQL은 크게 두 레이어로 구성됩니다:

스토리지 엔진은 인덱스 컬럼에 대한 단순 비교 조건(=, >, <, BETWEEN 등)만 처리할 수 있습니다. 이를 넘어서는 조건들은 MySQL 서버 레이어에서 추가로 걸러집니다.

알아야 할 배경 개념

1. MySQL의 레이어 구조

MySQL은 플러그인 방식의 스토리지 엔진 아키텍처를 사용합니다. 클라이언트 요청은 다음 흐름을 거칩니다:

  1. 클라이언트 → MySQL 서버 레이어 (SQL 파싱, 쿼리 최적화)
  2. MySQL 서버 → 스토리지 엔진 (InnoDB, MyISAM 등)
  3. 스토리지 엔진 → 데이터 파일 (레코드 읽기/쓰기)

스토리지 엔진은 "이 인덱스로 이 범위의 레코드를 읽어와"라는 명령만 이해합니다. 복잡한 WHERE 조건, 함수 호출, 서브쿼리 등은 MySQL 서버 레이어의 몫입니다.

2. 인덱스 조건 vs 필터 조건

EXPLAIN에서 keyExtra 컬럼을 보면 어디서 필터링이 일어나는지 알 수 있습니다:

더 깊이 파고들기

스토리지 엔진에서 처리되는 조건

MySQL 서버 레이어에서만 처리되는 조건 (Using where)

실무 예시

SELECT * FROM users 
WHERE age >= 30 
  AND YEAR(created_at) = 2026;

이 쿼리에서:

성능 영향

스토리지 엔진에서 필터링되지 못하면, 불필요한 레코드까지 MySQL 서버로 올라와 추가 처리 비용이 발생합니다. 예를 들어:

-- 나쁜 예: 함수 사용으로 인덱스 미사용
WHERE YEAR(created_at) = 2026

-- 좋은 예: 범위 조건으로 변경해 인덱스 사용
WHERE created_at >= '2026-01-01' 
  AND created_at < '2027-01-01'

ICP (Index Condition Pushdown)의 역할

MySQL 5.6부터 도입된 ICP는 일부 조건을 스토리지 엔진으로 "푸시다운"해서 MySQL 서버로 올라오는 레코드 수를 줄입니다. 하지만 함수나 서브쿼리는 여전히 푸시다운되지 않습니다.

시각화
클라이언트 쿼리 MySQL 서버 레이어 서버 레이어 필터링 • 함수: YEAR(), CONCAT() • 연산: col * 1.1 > 100 • 서브쿼리, 조인 조건 • 비인덱스 컬럼 조건 스토리지 엔진으로 푸시다운 • 인덱스 직접 비교: col = 10 • 범위: col BETWEEN 10 AND 20 • ICP 조건 (일부) → 스토리지 엔진에서 필터링 스토리지 엔진 (InnoDB) 인덱스 기반 레코드 읽기 WHERE age >= 30 → age 인덱스 사용 일치하는 레코드만 MySQL 서버로 반환 ✓ 필터링된 레코드 반환

쿼리 조건 중 인덱스를 사용할 수 있는 것은 스토리지 엔진에서 필터링되고, 함수/연산 등 복잡한 조건은 MySQL 서버 레이어에서 처리됩니다.

조건별 처리 위치
조건 예시 처리 위치 EXPLAIN Extra
WHERE age = 30 스토리지 엔진 (없음 - 인덱스 사용)
WHERE age BETWEEN 20 AND 40 스토리지 엔진 (없음 - 범위 스캔)
WHERE name LIKE 'Kim%' 스토리지 엔진 (없음 - 인덱스 범위)
WHERE name LIKE '%Kim%' MySQL 서버 Using where
WHERE YEAR(created) = 2026 MySQL 서버 Using where
WHERE salary * 1.1 > 50000 MySQL 서버 Using where
WHERE id IN (SELECT ...) MySQL 서버 Using where
WHERE age > 30 AND city = 'Seoul' (ICP) 스토리지 엔진 (일부) Using index condition
WHERE non_indexed = 'val' MySQL 서버 (풀 스캔 후) Using where
실무 최적화 팁

1. 함수를 피하고 범위 조건으로 변경

-- 나쁜 예
WHERE DATE_FORMAT(created_at, '%Y-%m') = '2026-03'

-- 좋은 예
WHERE created_at >= '2026-03-01' 
  AND created_at < '2026-04-01'

2. 연산은 우변으로 이동

-- 나쁜 예
WHERE salary * 1.1 > 50000

-- 좋은 예
WHERE salary > 50000 / 1.1

3. EXPLAIN으로 확인

Using where가 표시되면 MySQL 서버 레이어에서 추가 필터링이 일어난다는 신호입니다. 가능하면 조건을 인덱스로 푸시다운할 수 있도록 쿼리를 재작성하세요.

4. ICP 활용

복합 인덱스의 뒷부분 컬럼 조건은 ICP를 통해 스토리지 엔진으로 푸시다운될 수 있습니다. optimizer_switch에서 index_condition_pushdown=on인지 확인하세요.

함께 알면 좋은 개념