
개인 프로젝트에서 복합 인덱스 설계, DB쿼리 최적화, 캐시를 사용하여 조회 성능을 향상시킨 경험이있다.
이에 조회 성능을 향상시키기 위해 캐시 말고 어떤 방법이 있을까요? 라는 질문을 던질 수 있다.
무엇이 있을까?
파티셔닝과 샤딩 둘 다 조회 성능 향상의 중요한 수단이다. 하지만 작동 방식이 다르고 도입 비용도 차이가 난다.

: 하나의 큰 테이블을 논리적/물리적으로 여러 조각으로 나누는 것. 같은 DB 인스턴스 안에서.
Partition Pruning (파티션 가지치기)
click_logs 테이블이 1억건, 월별로 파티션돼 있다고 가정해보자.
(p_2025_01, p_2025_02, ..., p_2025_12)
select count(*) from click_logs
where create_at between '2025-03-01' and ''2025-03-31';
-> MySQL이 '이 쿼리는 p_2025_03 파티션만 보면 된다'라고 판단하고 나머지 11개 파티션은 아예 스캔하지 않는다. 1억 건 -> 800만 건만 봄.
인덱스만 있어도 빠르긴 한데, 파티셔닝은 물리적으로 데이터 범위를 분리해서 I/O 자체 원천 차단한다.
| 종류 | 기준 | 예시 |
|---|---|---|
| Range | 값의 범위 | 날짜별 (월별/연도별) |
| List | 명시적 값 목록 | 지역별(서울/부산/대구) |
| Hash | 해시값 | user_id % 4 |
| Key | DB가 자동 해싱 | Hash와 유사 |
DROP PARTITION p_2023_01은 즉시 수행 vs DELETE WHERE date < ...은 느리다.
shard : (유리,금속 등의) 조각[파편]
: 데이터를 여러 DB(인스턴스)에 분산 저장하는 것. 파티셔닝의 "수평 확장 버전"이라고 보면 된다.
[파티셔닝] [샤딩]
DB Server 1 DB Server 1 DB Server 2 DB Server 3
├─ p_2025_01 └─ user 1~1M └─ user 1M~2M └─ user 2M~3M
├─ p_2025_02
├─ p_2025_03
사용자 요청 ───┬──→ 샤드1 (user_id 1~1M 처리)
├──→ 샤드2 (user_id 1M~2M 처리)
└──→ 샤드3 (user_id 2M~3M 처리)
→ 3개 서버가 동시에 다른 요청을 처리
→ 총 처리량 3배
[이상적인 분산] [핫스팟 발생]
샤드1: ████ (33%) 샤드1: ██████████ (90%) ← 죽기 직전
샤드2: ████ (33%) 샤드2: █ (5%)
샤드3: ████ (33%) 샤드3: █ (5%)
분산 시스템에서 핫스팟 : 여러 서버 중 특정 서버에만 요청/데이터가 집중되는 현상
샤딩의 목적은 부하를 고르게 분산하는 건데, 한쪽 샤드만 일이 많고 나머지는 놀고 있으면 샤딩의 의미가 사라진다. 핫스팟이 생기면 그 샤드만 부하가 폭주해서 응답 지연/장애가 발생하고, 나머지 샤드의 자원은 놀고 있는 비효율이 생긴다.
hash(user_id) % N으로 분산 (균등 분배, 샤드 추가 시 재분배 어려움)"분산 트랜잭션은 가능하면 피하자" 샤딩 설계 시 트랜잭션이 한 샤드 안에서 끝나도록 데이터 모델을 설계하는 것이 우선이다. 같이 변경되는 데이터는 같은 샤드에 둔다. 이걸 실패하면 2PC or Saga 적용해야 하는데 비용이 크다.
샤딩은 단순히 "데이터를 나누는 기술"이 아니라, 시스템 전체의 설계, 개발, 운영 방식을 모두 바꾸는 결정이다. 그래서 인덱스 -> Read Replica -> 파티셔닝 -> 캐시 -> ... 모든 단계를 거친 뒤 마지막 카드로 꺼내야 한다.
| 항목 | 파티셔닝 | 샤딩 |
|---|---|---|
| 위치 | 단일 DB 서버 내부 | 여러 DB 서버에 분산 |
| 자원 확장 | ❌ (CPU/디스크 공유) | ✅ (서버 수만큼 확장) |
| JOIN | 가능 | 매우 어려움 |
| 트랜잭션 | 일반 트랜잭션 | 분산 트랜잭션 필요 |
| 도입 난이도 | 중간 | 매우 높음 |
| 주 목적 | 큰 테이블 관리 + 조회 최적화 | 수평 확장(Scale-Out) |
1. 인덱스 / 쿼리 튜닝 : 가장 먼저 시도
2. Read Replica (읽기 분산) : 읽기 부하가 큰 경우
3. 파티셔닝 : 단일 테이블이 너무 커진 경우
4. 캐시(Redis) : 반복 조회 패턴이 명확할 때
5. 샤딩 : 위 모든 게 한계에 도달했을 때 (최후의 수단)
파티셔닝과 샤딩 둘 다 조회 성능 향상에 사용된다. 다만 작동 원리와 도입 비용이 달라서 적용 시점이 다르다.
파티셔닝은 단일 DB 안에서 큰 테이블을 논리적으로 분할하는 방식이다. 핵심은 Partition Pruning으로, WHERE 조건에 파티션 키가 들어오면 해당 파티션만 스캔하고 나머지는 건너뛴다.
예를 들어 클릭 이벤트 로그처럼 시간 기반 데이터에 월별 Range 파티셔닝을 적용하면, 특정 월 조회시 다른 티션은 아예 보지 않으니 I/O가 크게 줄어든다. 인덱스와 함께 쓰면 큰 테이블의 조회를 효과적으로 가속할 수 있다.
샤딩은 데이터를 여러 DB 서버에 분산 저장하는 방식이라, 파티셔닝과 달리 CPU/메모리/디스크 자원 자체가 샤드 수만큼 늘어난다. 단일 서버의 한계를 넘어 수평 확장이 필요할 때 도입한다. 다만 샤드 간 JOIN, 분산 트랜잭션, 핫스팟 문제 등 복잡도가 매우 커지기 때문에, 일반적으로는 인덱스 -> Read Replica -> 파티셔닝 -> 캐시까지 다 검토한 뒤 마지막에 고려하는 카드이다.
현재 개인프로젝트에서 1,000만건의 데이터의 조회 성능을 개선하기 위해 인덱스 최적화, Redis 캐싱 단계까지 적용했지만, 클릭 이벤트 수가 수억 건 단위로 늘어나는 시점에서는 created_at 기반 Range 파티셔닝을 먼저 검토할 수 있겠다.
Q. 파티셔닝과 인덱스의 차이가 무엇인가?
: 인덱스는 데이터의 "위치를 빠르게 찾는 자료구조"이고, 파티셔닝은 데이터 자체를 "물리적으로 나누는 것"이다. 인덱스도 결국 트리를 타고 내려가야 하지만, 파티셔닝은 아예 다른 파일/테이블 영역을 보지 않게 한다. 보통 둘을 함께 사용한다.
Q. 샤딩 키는 어떻게 정해야 할까?
: 카티널리티(행의 개수)가 높아야 하고(고르게 분산), 대부분의 쿼리가 그 키를 포함해야 하며(샤드 라우팅 가능), 핫스팟이 생기지 않아야 한다. 잘못 고르면 한 샤드만 부하가 몰려서 샤딩의 의미가 사라진다.
Q. Redis Cluster도 샤딩을 쓰나?
: Consistent Hashing 기반으로 16384개의 해시 슬롯에 키를 분산시킨다. 노드 추가/제거 시 일부 슬롯만 이동시키기 때문에 리밸런싱 부담이 적다.
여러 Redis 노드를 묶어 하나의 분산 캐시처럼 동작하게 하는 솔루션이 Redis Cluster이다.
[애플리케이션] │ ┌─────────────┼─────────────┐ │ │ │ [Redis Node 1] [Redis Node 2] [Redis Node 3] (16GB) (16GB) (16GB) → 총 48GB 메모리, 처리량 3배