🏗️ 대규모 시스템 설계 강의 정리 (섹션 2)
인프런 강의 섹션 2: 데이터베이스 구조와 확장 전략 학습 내용 정리
기간: 8월 18일 ~ 8월 26일
📅 8월 18일 (월) — 샤딩(Sharding)
🔹 샤딩이란?
- 데이터를 여러 DB에 분산 저장하는 기술
- 가용성을 높이기 위한 Master-Slave 구조와는 목적이 다름
- 샤딩은 데이터 분산과 확장성을 위한 구조
🔹 샤딩의 종류
- 수직 샤딩(Vertical Sharding): 테이블 단위로 기능별 DB 분리 예) 사용자, 결제, 게시판 DB를 각각 분리
- 수평 샤딩(Horizontal Sharding): 한 테이블의 데이터를 여러 DB에 나누어 저장 예) user_id 범위별로 다른 DB에 저장
🔹 샤딩 키(Sharding Key)의 중요성
- 어떤 기준으로 데이터를 분산할지 결정하는 핵심 포인트
- 잘못된 샤딩 키는 전체 DB를 탐색하게 만들어 성능 저하 유발
- 예시:
- DC Inside 같은 게시판 구조
- “야구 갤러리”의 글과 댓글 데이터가 있을 때, → 게시판 ID(board_id)를 샤딩 키로 설정하는 것이 효율적
- 만약 글 ID(article_id)를 샤딩 키로 쓴다면, 특정 게시판 조회 시 모든 DB를 뒤져야 할 수도 있음
🔹 AWS DynamoDB의 사례
- DynamoDB는 해싱 키만 지정하면 내부적으로 샤딩을 자동 처리
- 애플리케이션에서 직접 샤딩 로직을 구현할 필요가 없음
🔹 PK 생성 전략: Snowflake 알고리즘
- 오름차순 + 유니크한 숫자를 생성하는 알고리즘
- 분산 환경에서 충돌 없이 정렬 가능한 ID 생성 가능
- 이후 강의에서 자세히 다룸
📅 8월 21일 (목) — 인덱스 구조와 페이지네이션
🔹 InnoDB 인덱스 구조
- InnoDB는 테이블마다 Clustered Index를 자동 생성
- Clustered Index의 leaf node는 실제 행 데이터(row)를 저장
- 일반적으로 Primary Key가 Clustered Index로 설정됨
- 우리가 생성하는 인덱스는 Secondary Index
| 구분 | Leaf Node 내용 | 데이터 접근 방식 |
|---|
| Clustered Index | 실제 Row 데이터 | 직접 접근 |
| Secondary Index | 인덱스 컬럼 + PK 포인터 | PK → Row 접근 |
🔹 커버링 인덱스(Covering Index)
- 조회 쿼리에서 필요한 컬럼이 모두 인덱스에 포함되어, 테이블 접근 없이 인덱스만으로 조회 가능한 경우
SELECT *
FROM (
SELECT article_id
FROM article
WHERE board_id = 1
ORDER BY article_id DESC
LIMIT 30 OFFSET 149970
) t
LEFT JOIN article ON t.article_id = article.article_id;
→ 서브쿼리에서 커버링 인덱스를 사용하고, 본 테이블을 LEFT JOIN하는 방식
🔹 Offset 기반 페이지네이션의 한계
- Offset이 클수록 Index Scan 비용이 증가
- 실제 데이터 접근 없이 인덱스만 타더라도 느려질 수밖에 없음
🔹 개선 방안
-
데이터 분리
- 예: 게시글을 연도별 테이블로 분리 (article_2024, article_2025 등)
-
메타데이터 관리
- 테이블별 게시글 개수를 미리 저장 → offset 범위 벗어나면 테이블 스킵
-
정책적 제약
📅 8월 23일 (토) — Count 쿼리 최적화
🔹 페이지 번호 기반 페이지네이션의 문제
- 게시글 개수를 표시하기 위해 COUNT(*) 쿼리를 실행
- 커버링 인덱스를 사용하더라도, 모든 게시글 수를 세야 하므로 느림
🔹 꼭 전체 개수가 필요할까?
- 대부분의 서비스는 최대 이동 가능한 페이지 수가 제한됨
- 예: 현재 1페이지에서 1~10페이지만 이동 가능
🔹 페이지 계산 공식
최대 이동 가능한 페이지 수(k), 현재 페이지(n), 페이지당 게시글 수(m)
(((n - 1) / k) + 1) * m * k + 1
🔹 Count 쿼리 최적화 예시
SELECT COUNT(*)
FROM (
SELECT article_id
FROM article
WHERE board_id = {board_id}
LIMIT {limit}
) t;
→ 일부 데이터만 대상으로 count 수행 (성능 개선)
📅 8월 26일 (화) — PK 생성 전략
🔹 1. DB Auto Increment
- 단일 DB에서는 간편하지만, 분산 환경에서는 PK 중복 발생 가능
- 클라이언트 노출 시 보안 이슈 발생
- UUID를 별도 Unique Index로 사용하는 것도 가능하나,
- Secondary → Clustered Index 접근이 필요해 조회 비용 증가
🔹 2. 유니크 문자열 / 난수 (UUID 등)
- UUID, Random String 등을 PK로 지정 가능
- 하지만 랜덤성으로 인해 성능 저하 발생
- Clustered Index는 정렬 구조 유지 필요 → 중간 삽입 시 B+ Tree 재구성 발생
- 범위 조회 시 랜덤 I/O 증가
🔹 3. 유니크 정렬 문자열 (예: ULID)
- 분산 환경에서도 중복 없음
- 정렬 가능 → 랜덤 I/O 감소
- 보안성도 확보
- 일반적으로 128비트 사용 → 데이터 크기에 따라 성능/공간 트레이드오프 존재
🔹 4. 유니크 정렬 숫자 (예: Snowflake)
- 64비트 정렬 숫자 기반 ID 생성 알고리즘
- 분산 환경 중복 문제 해결
- 정렬 및 유니크 보장
- 대규모 시스템에서 PK로 널리 사용됨 (Twitter, Kakao 등)
🧭 마무리
이번 섹션에서는 데이터베이스 확장성과 인덱스 구조, PK 설계 전략을 중심으로 다뤘습니다.
단순히 쿼리 튜닝을 넘어, 데이터가 커질 때 시스템이 어떻게 확장될 수 있는지를 고민하게 되는 구간입니다.
🔗 참고 링크: Perplexity 검색 결과
노트에 정리해둔 내용 GPT 사용하여 재정리함
