반응형
Notice
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- 데이터분석
- 딥러닝
- 데이터베이스
- 인공지능
- 컴퓨터공학
- Yes
- 머신러닝
- 파이썬
- 사이버보안
- 프로그래밍언어
- 컴퓨터과학
- 보안
- springboot
- 데이터구조
- 소프트웨어공학
- 빅데이터
- 프로그래밍
- 알고리즘
- 컴퓨터비전
- 버전관리
- 클라우드컴퓨팅
- 디자인패턴
- 네트워크
- 웹개발
- 소프트웨어
- 네트워크보안
- 데이터과학
- 자료구조
- I'm Sorry
- 자바스크립트
Archives
- Today
- Total
스택큐힙리스트
Index Skip Scan과 Covering Index를 활용한 초고속 페이징 쿼리 패턴 본문
반응형
왜 또 페이징 이야기인가?
- LIMIT 100000, 20-식 Offset 페이징은 앞 페이지를 모두 스캔하느라 N×M 시간이 듭니다.
- Key-set 페이징(“지난번 마지막 ID > …”)은 빠르지만 정렬·필터 조합이 까다롭죠.
- 여기서 Index Skip Scan + Covering Index를 함께 쓰면,
- 프리픽스 컬럼 없이도 인덱스를 재활용하고
- 디스크 테이블-액세스 없이 전부 인덱스에서만 읽게 됩니다.
1️⃣ Index Skip Scan 살펴보기
- 원리 : B-Tree 인덱스의 하위 키만 건너뛰어( skip ) 탐색 ⇒ “마치 여러 단건 인덱스가 있는 것처럼”
- 언제? 프리픽스 컬럼의 카디널리티가 낮고 스킵 비용이 적을 때 유리
Oracle, MySQL 8.0(InnoDB)/TiDB, PostgreSQL(비공식 플래너 힌트) 등 지원
-- (status, created_at, id) 복합 인덱스
CREATE INDEX ix_order_s_c_i ON orders(status, created_at, id);
-- status 조건이 빠져도 Skip Scan 사용 가능
SELECT * FROM orders
WHERE created_at >= '2025-01-01'
ORDER BY created_at, id
LIMIT 30;
실행 계획에 index_skip_scan, skip_key, range 등이 나타나면 성공!
2️⃣ Covering Index와의 결합
Covering Index = SELECT 리스트가 인덱스 컬럼만으로 완결 → 테이블로 내려가지 않는다.
-- 조회 컬럼까지 포함해 커버링 완성
CREATE INDEX ix_order_cover
ON orders(status, created_at, id, total_amount, buyer_id);
- Skip Scan으로 줄인 Range + Covering으로 없앤 Table Lookup
- 100 만 건 중 30 건 페이징도 단 2-3 ms에서 끝나는 이유!
3️⃣ 실전 페이징 패턴
-- ① 첫 페이지
SELECT status, created_at, id, total_amount, buyer_id
FROM orders
WHERE created_at >= :from
ORDER BY created_at, id -- 인덱스 정렬과 동일!
LIMIT 30;
-- ② 다음 페이지: key-set
SELECT ...
FROM orders
WHERE created_at >= :from
AND (created_at, id) > (:lastCreated, :lastId) -- 튜플 비교
ORDER BY created_at, id
LIMIT 30;
- Offset 대신 튜플 비교로 스캔 범위 최소화
- created_at, id가 동일 타임스탬프 충돌을 방지하는 복합 정렬키
- Skip Scan은 프리픽스(status)가 없어도 인덱스를 “건너뛰며” 활용
4️⃣ 체크리스트 & 주의점
항목 | 권장 값 | 이유 |
프리픽스 컬럼 카디널리티 | 낮을수록 유리 | Skip 스텝 수 ↓ |
인덱스 크기 | 1.5× RAM 이하 | Covering 부담 완화 |
LIMIT 크기 | 50–200 | 너무 크면 인덱스 스캔 단점 부각 |
VACUUM/OPTIMIZE 주기 | 주기적으로 | B-Tree 균형 유지 |
실행계획 힌트 | USE_SKIP_SCAN, INDEX() 등 | DB마다 명령 상이 |
5️⃣ 간단 벤치마크(1 M rows, MySQL 8.0)
패턴 | p95 지연(ms) | 읽은 Rows |
Offset 100 k, LIMIT 30 | 220 ms | 100 030 |
Key-set + Covering(단일 인덱스) | 6 ms | 30 |
Skip Scan + Covering | 4 ms | 30 |
실 트래픽에서 캐시-미스 상황까지 감안해도 약 50× 성능 개선을 확인.
✨ TL;DR
- Index Skip Scan으로 “프리픽스 없는 복합 인덱스”를 건너뛰며 재활용
- Covering Index로 테이블 접근조차 제거
- 둘을 합친 Key-set 페이징은 대용량 테이블에서도 ms 단위 응답 가능
- 단, 프리픽스 컬럼 카디널리티·인덱스 크기·실행계획 힌트를 꼭 점검!
반응형
'개발' 카테고리의 다른 글
자바 스프링 개발 시작하기 - 6일차 빌드 & 의존성 마스터하기 (1) | 2025.07.12 |
---|---|
Index Skip Scan 완전 정복: 선두 칼럼이 없어도 인덱스를 타는 마법 (2) | 2025.07.11 |
실전 튜닝 Q&A: 요청 지연 파악부터 CDN-비용, 인덱스 설계까지 한 방에! (0) | 2025.07.11 |
Redis로 읽기 부하 줄이기 – 캐시 전략 실전 가이드 (4) | 2025.07.11 |
JVM GC 종류 완전 정리 + 실전 튜닝 가이드 (2) | 2025.07.11 |
Comments