G 세트

#14. ICP(Index Condition Pushdown)

스토리지 엔진에 필터링을 맡기기

학습자료를 불러오는 중...

#14. ICP(Index Condition Pushdown)

스토리지 엔진에 필터링을 맡기기

# Index Condition Pushdown — 스토리지 엔진에 필터링을 맡기기 > 📘 **학습자료 15편** | 연결 퀴즈: [**인덱스 고급1 풀러가기**](quiz.html?set=G) > MySQL 5.6부터 도입된 최적화 기법. > "인덱스에 있는 컬럼이지만 인덱스 탐색 조건으로는 못 쓰는" 애매한 조건들을, 스토리지 엔진이 **인덱스 안에서 미리 걸러주는** 기법입니다. > 이걸 알면 EXPLAIN의 `Using index condition` 한 줄이 갑자기 의미를 가지기 시작합니다. > 📚 **이전 편**: [14편 - 인덱스와 정렬] > 9편의 `Using index` / `Using where` / `Using index condition` 셋 중에서, > 마지막 하나가 이번 편의 주제입니다. 9편을 한 번 더 떠올리면 도움이 됩니다. ## 이 자료를 다 읽으면 알게 되는 것 - MySQL이 **MySQL 엔진**과 **스토리지 엔진**으로 나뉘어 동작한다는 사실 - ICP가 없을 때(MySQL 5.5 이하) 발생했던 **불필요한 랜덤 I/O** 문제 - ICP가 있을 때(5.6+) 어떻게 그 문제를 해결하는지 - EXPLAIN의 `Using index condition`이 의미하는 것 --- ## 📑 목차 - [1. MySQL의 두 층: MySQL 엔진과 스토리지 엔진](#1-mysql의-두-층-mysql-엔진과-스토리지-엔진) - [⭐ 2. ICP가 없을 때의 문제](#2-icp가-없을-때의-문제) - [⭐ 3. ICP가 있을 때: 스토리지 엔진에 필터링을 맡긴다](#3-icp가-있을-때-스토리지-엔진에-필터링을-맡긴다) - [4. EXPLAIN으로 ICP 식별하기](#4-explain으로-icp-식별하기) - [5. ICP를 끄고 비교해보기](#5-icp를-끄고-비교해보기) - [핵심 요약](#핵심-요약) --- ## 1. MySQL의 두 층: MySQL 엔진과 스토리지 엔진 ICP를 이해하려면 먼저 MySQL의 내부 구조를 한 번 짚어야 합니다. MySQL은 **두 개의 층**으로 동작합니다. ![MySQL 엔진과 스토리지 엔진의 관계](https://quiz-solution-images.s3.ap-northeast-2.amazonaws.com/quiz48/48-1.png) MySQL 엔진이 "이런 데이터 가져와줘" 라고 시키면, 스토리지 엔진이 가져옵니다. 둘은 **인터페이스를 통해 통신**합니다. 여기서 중요한 점: **"무엇을 어디까지 스토리지 엔진에 맡기느냐"** 가 성능에 큰 영향을 미칩니다. 스토리지 엔진이 미리 걸러서 적은 양만 올려보내면 효율적이고, 많이 올려보내고 MySQL 엔진이 일일이 거르면 비효율적이죠. 이 분배 방식의 변화가 ICP의 핵심입니다. --- ## 2. ICP가 없을 때의 문제 > ⭐ **이 섹션이 ICP의 필요성을 이해하는 핵심입니다.** 다음 상황을 봅시다. ```sql -- (num, name) 복합 인덱스 존재 SELECT * FROM test_icp WHERE num = 1 AND name LIKE '%q'; -- ← 좌측 와일드카드, 인덱스 탐색 불가 ``` 조건을 살펴보면: - `num = 1`: 동등 조건. 인덱스 탐색에 사용 가능 - `name LIKE '%q'`: 좌측 와일드카드. **인덱스 탐색에 사용 불가** (8편 참고) 근데 `name`은 인덱스에 포함되어 있긴 합니다. 그러나, Left-Most 정렬의 특성으로 인덱스를 효율적으로 활용하지는 못하고 한행한행 탐색이 필요합니다. ### MySQL 5.5 이전: 조건 자체를 스토리지 엔진에 안 넘김 5.5 이전 MySQL은 이렇게 동작했습니다: ![ICP 없는 동작 - 인덱스로 num만 좁힘](https://quiz-solution-images.s3.ap-northeast-2.amazonaws.com/quiz48/48-2.png) 1. MySQL 엔진이 `num = 1` 조건만 스토리지 엔진에 전달 2. 스토리지 엔진이 인덱스로 `num = 1`인 행들 찾기 (예: 1,000건) 3. 각 PK로 클러스터링 인덱스에 가서 **실제 데이터 행 가져오기** (1,000번의 랜덤 I/O) 4. 1,000건을 MySQL 엔진에 전달 5. MySQL 엔진이 `name LIKE '%q'` 조건을 한 건 한 건 검사 ![ICP 없는 동작 - MySQL 엔진이 사후 필터링](https://quiz-solution-images.s3.ap-northeast-2.amazonaws.com/quiz48/48-3.png) ### 무엇이 문제인가 만약 `name LIKE '%q'`까지 만족하는 행이 **단 3건**뿐이라면? **나머지 997건은 헛수고**입니다. 역시나 **불필요한 랜덤 I/O**문제가 생깁니다. `name` 정보가 인덱스에 있는데도 활용을 못 하니까, 일단 테이블에 다녀와서 검사하게 됩니다. > ⚠️ **여기서 중요한 점** > `name` 조건이 "인덱스 탐색"으로는 못 써도, "인덱스에서 값을 읽어 비교"하는 건 가능합니다. > 5.5 이전에는 이 차이를 활용하지 못했고, ICP는 정확히 이 부분을 개선합니다. --- ## 3. ICP가 있을 때: 스토리지 엔진에 필터링을 맡긴다 > ⭐ **이게 ICP의 핵심 아이디어입니다.** MySQL 5.6부터는 위 시나리오가 다음과 같이 바뀝니다. ![ICP 있는 동작 - 스토리지 엔진이 인덱스에서 필터링](https://quiz-solution-images.s3.ap-northeast-2.amazonaws.com/quiz48/48-4.png) 1. MySQL 엔진이 `num = 1` **그리고** `name LIKE '%q'` 조건을 둘 다 스토리지 엔진에 전달 2. 스토리지 엔진이 인덱스로 `num = 1`인 항목 찾기 (1,000건) 3. **그 1,000건의 인덱스 안에서 `name LIKE '%q'`를 미리 검사** → 3건만 통과 4. 그 3건의 PK로 클러스터링 인덱스에 다녀와서 데이터 가져오기 (3번의 랜덤 I/O) 5. 3건만 MySQL 엔진에 전달 ### 무엇이 달라졌나 | 단계 | ICP 없음 | ICP 있음 | |---|---|---| | 인덱스에서 좁힘 | 1,000건 | 1,000건 (동일) | | 테이블 다녀오기 | **1,000번** | **3번** | | MySQL 엔진이 받는 양 | 1,000건 | 3건 | | MySQL 엔진의 사후 필터링 | 필요 (1,000건 검사) | 불필요 | 랜덤 I/O가 **1,000번 → 3번** 으로 줄었습니다. 약 333배 차이. ### 핵심을 한 줄로 > 🎯 **인덱스로 직접 탐색은 못 해도, 인덱스에 있는 값이라면 스토리지 엔진이 인덱스 안에서 미리 걸러낼 수 있다.** > 이 작업을 MySQL 엔진이 아닌 스토리지 엔진에 "밀어내려(push down)" 보낸다고 해서 **Index Condition Pushdown** 입니다. > 💡 **인덱스에 있는 컬럼이어야 한다는 점이 중요** > 인덱스에 없는 컬럼의 조건은 ICP 대상이 아닙니다. 스토리지 엔진이 인덱스만 보고 판단할 수 없으니까요. > 위 예시에서 `name`이 `(num, name)` 인덱스에 포함되어 있어서 가능했던 겁니다. --- ## 4. EXPLAIN으로 ICP 식별하기 ICP가 적용됐는지 확인하는 방법은 EXPLAIN의 `Extra` 컬럼입니다. ```sql EXPLAIN SELECT * FROM test_icp WHERE num = 1 AND name LIKE '%q'; ``` | id | type | key | rows | filtered | Extra | |---|---|---|---|---|---| | 1 | ref | idx_num_name | 9 | 11.11 | **Using index condition** | **`Using index condition`** — 이게 ICP의 명시적 신호입니다. ### 9편의 세 가지 키워드 다시 보기 9편에서 본 `Extra`의 세 가지 키워드를 ICP까지 포함해서 정리하면: | Extra | 의미 | 비유 | |---|---|---| | `Using index` | 커버링 인덱스 — 인덱스만으로 답이 나옴 | 사전만 보고 끝 | | `Using index condition` | ICP — 스토리지 엔진이 인덱스에서 추가 필터링 | 사전에서 걸러서 일부만 책장에 다녀옴 | | `Using where` | MySQL 엔진이 사후 필터링 | 책장에서 다 가져온 다음 거르기 | 세 키워드가 단계적으로 이어집니다: - 가장 빠른 건 `Using index` (테이블 안 다녀옴) - 그 다음이 `Using index condition` (테이블에 적게 다녀옴) - 가장 느린 건 `Using where` (다 다녀온 후 거름) 같은 쿼리도 인덱스 설계와 MySQL 버전에 따라 이 셋 중 어느 쪽이든 될 수 있습니다. --- ## 5. ICP를 끄고 비교해보기 ICP가 실제로 효과가 있는지 확인하려면, ICP를 꺼서 5.5 시절의 동작을 재현해볼 수 있습니다. ```sql -- ICP 끄기 SET optimizer_switch = 'index_condition_pushdown=off'; ``` 이 상태에서 같은 쿼리를 EXPLAIN 해보면: | id | type | key | rows | filtered | Extra | |---|---|---|---|---|---| | 1 | ref | idx_num_name | 9 | 11.11 | **Using where** | `Extra`가 `Using index condition`에서 `Using where`로 바뀌었습니다. ICP 없이 MySQL 엔진이 사후 필터링을 한 모습입니다. > 💡 **실무 팁** > 일반적으로 ICP는 **켜두는 게 거의 항상 유리**합니다. MySQL 8.0에서는 기본 ON. > 끄는 경우는 매우 특수한 케이스(특정 쿼리에서 옵티마이저가 잘못된 판단을 할 때)에 한정됩니다. > 평소엔 신경 쓸 필요 없고, EXPLAIN에서 `Using index condition`이 보이면 "잘 동작하고 있구나" 정도로 이해하면 됩니다. --- ## 핵심 요약 이번 편에서 꼭 가져가야 할 한 가지: > 🎯 **인덱스에 포함된 컬럼이라면, 인덱스 탐색 조건으로 못 쓰더라도 스토리지 엔진이 인덱스 안에서 미리 걸러줄 수 있다** > 이게 ICP. EXPLAIN의 `Using index condition`으로 확인. MySQL 5.6+에서 기본 ON. 체크리스트: - [x] MySQL이 MySQL 엔진과 스토리지 엔진의 두 층으로 동작한다는 걸 안다 - [x] EXPLAIN의 `Using index condition`을 보고 의미를 안다 - [ ] ICP가 없으면 발생하는 불필요한 랜덤 I/O 문제를 설명할 수 있다 - [ ] `Using index` / `Using index condition` / `Using where`의 차이를 안다 - [ ] 인덱스에 포함된 컬럼의 조건이어야 ICP가 적용된다는 제약을 안다 > 📝 체크리스트를 다 채울 자신이 있다면? [**인덱스 고급1 퀴즈 도전하기**](quiz.html?set=G) --- ## 이제 퀴즈에 도전하기 고급1 시리즈를 모두 마쳤습니다. 14편과 15편을 합쳐 고급1 퀴즈에 필요한 개념을 다뤘습니다. - 인덱스의 정렬 성질을 ORDER BY에 그대로 활용 (14편) - ASC는 정순 스캔, DESC는 역순 스캔 (`Backward index scan`) (14편) - 정순이 역순보다 빠른 이유 + 8.0+ 내림차순 인덱스 (14편) - MySQL의 두 층 구조와 ICP의 의미 (15편) - ICP의 명시적 신호 `Using index condition` (15편) > 🎯 [**인덱스 고급1 퀴즈 풀어보기**](quiz.html?set=G) > 막히는 게 있다면 해당 학습자료의 섹션으로 돌아와 다시 읽어보세요. > 고급1의 핵심은 **EXPLAIN의 `Extra` 컬럼이 들려주는 이야기를 끝까지 듣는 것** 입니다. > `Using index`, `Using index condition`, `Using where`, `Backward index scan`, `Using filesort` — 이 다섯 키워드를 자신 있게 구분할 수 있다면 인덱스 진단의 90%는 됩니다. --- ## Reference - MySQL 공식 문서: [Index Condition Pushdown Optimization](https://dev.mysql.com/doc/refman/8.4/en/index-condition-pushdown-optimization.html) - MySQL 공식 문서: [EXPLAIN Output Format](https://dev.mysql.com/doc/refman/8.4/en/explain-output.html) - 참고 글: [Index Condition Pushdown 이해하기 (jojoldu)](https://jojoldu.tistory.com/474)

이 세트 퀴즈 풀기 | 홈으로 돌아가기