본문으로 건너뛰기
김신건의 로그

[DB] DynamoDB: PK + SK, single-table design, GSI / LSI

· 수정 · 📖 약 2분 · 812자/단어 #dynamodb #nosql #aws #key-value #document
DynamoDB, DDB, partition key, sort key, GSI, LSI, single-table design, DAX, PartiQL

정의

DynamoDB 는 AWS 의 fully managed key-value + document NoSQL. low-latency, infinite scale, schemaless. single-table design 이 트레이드마크 패턴.

핵심 키

Primary Key = Partition Key (PK)
           또는 Partition Key + Sort Key (PK + SK) ← Composite
의미
PK (Partition Key)hash → 물리 partition 결정
SK (Sort Key)같은 PK 안의 정렬 키

IMPORTANT

DynamoDB 의 모든 query 는 PK 를 반드시 지정. SK 는 range query 가능. 이 제약이 single-table design 을 강제.

Item 예시

PKSKTypeData
USER#42PROFILEusername, email
USER#42ORDER#2026-06-25#o_1ordertotal, items
USER#42ORDER#2026-06-24#o_2ordertotal, items
USER#42ADDR#homeaddresscity, street
ORDER#o_1METAorderuserId, status

한 테이블에 여러 entity type 동시 저장. 한 query 로 user 의 모든 데이터:

PK = USER#42  → 모든 row (PROFILE, ORDER, ADDR)
PK = USER#42 AND SK begins_with(ORDER#) → 주문만

Capacity Mode

모드의미
ProvisionedRCU/WCU 미리 설정
On-Demand자동 스케일, 사용량 청구
단위1 RCU1 WCU
Eventually consistent2 read/sec (4KB)-
Strongly consistent1 read/sec-
Write-1 write/sec (1KB)

Strongly vs Eventually Consistent Read

flowchart LR
    Write[Write] --> Leader[Leader replica]
    Leader -.async.-> R1[Replica 1]
    Leader -.async.-> R2[Replica 2]
    Read1[Strong read] --> Leader
    Read2[Eventual read] --> R1
    Read2 --> R2
StrongEventual
Latency약간 높음낮음
Cost (RCU)2배기본
일관성항상 최신최근 쓰기 못 봄 가능

GSI vs LSI

LSI (Local)GSI (Global)
PK같은 base table 의 PK임의 키
동시 생성create 시만언제든
일관성strong / eventualeventual 만
크기 제한10GB / PK없음
개수520
flowchart LR
    Base["Base table (PK, SK)"]
    Base --> LSI1["LSI (PK, new_SK)"]
    Base --> GSI1["GSI (different_PK, different_SK)"]

Single-Table Design

flowchart TB
    Q[모든 access pattern 정의]
    Q --> Choose[PK + SK 선택]
    Choose --> One[ONE table 에 모든 entity]
    One --> Why[*Join 없이* 한 query 로 끝]

IMPORTANT

RDB 사고 (테이블 = entity)완전 다른 패러다임. access pattern 을 먼저 정의, 그에 맞춰 PK/SK 디자인. 잘못 설계하면 전체 마이그레이션.

Query vs Scan

# Query (효율적, PK 필수)
QUERY PK = "USER#42" AND SK begins_with "ORDER#"

# Scan (전체 테이블 순회, 비효율)
SCAN FilterExpression: "status = paid"

WARNING

Scan 은 거의 항상 안티패턴. 모든 partition 순회 → 비용 폭발. Scan 이 자주 필요하면 디자인 결함.

DAX (DynamoDB Accelerator)

flowchart LR
    App --> DAX["DAX Cluster<br/>(in-memory cache)"]
    DAX -->|miss| DDB[(DynamoDB)]
    DAX -.->|hit| App
  • 마이크로초 단위 latency.
  • write-through 캐시.
  • 읽기 중심 워크로드에서 효과.

Streams + Lambda

flowchart LR
    DDB[(DynamoDB Table)] -->|change stream| Streams[DDB Streams]
    Streams --> Lambda[Lambda]
    Lambda --> ES[ElasticSearch]
    Lambda --> SNS[SNS]
    Lambda --> SQS[SQS]

Change Data Capture. secondary index 가 부족할 때 Streams 로 외부 검색 인덱스 동기화.

PartiQL

-- SQL-like 쿼리
SELECT * FROM "MyTable" WHERE PK = 'USER#42' AND begins_with("SK", 'ORDER#');

익숙한 SQL 문법이지만 내부는 여전히 PK/SK 제약 적용. RDB 쿼리처럼 작성하면 Scan 폭발.

흔한 함정

WARNING

  1. Hot partition = 특정 PK 에 트래픽 집중. 분산 키 디자인 (해시 prefix).
  2. 너무 큰 item = 400KB 제한. 큰 데이터는 S3 + DDB 에 참조.
  3. Scan 의존 쿼리 = 비용 폭발. GSI 추가.
  4. eventual consistency 무시 = 방금 쓴 값이 없을 수 있음. strong read 명시 또는 재시도.

TTL (Time to Live)

아이템에 ttl (Unix timestamp) 속성 추가 → 만료 시 자동 삭제. 만료 후 최대 48시간 내 삭제 (정확한 시각 미보장).

aws dynamodb update-time-to-live \
  --table-name Orders \
  --time-to-live-specification "Enabled=true,AttributeName=ttl"
import time
item = {
    'PK': 'SESSION#xyz',
    'SK': 'META',
    'ttl': int(time.time()) + 3600   # 1시간 후 만료
}

TIP

TTL 만료 전까지는 read 에서 필터링이 필요. DDB 는 만료 시각이 지나도 즉시 삭제 보장 안 됨.

Transactions

ACID 보장, 최대 100 item, 동일/다른 테이블 가능.

client.transact_write(
    TransactItems=[
        {
            'Put': {
                'TableName': 'Orders',
                'Item': {'PK': {'S': 'ORDER#1'}, 'status': {'S': 'PLACED'}},
                'ConditionExpression': 'attribute_not_exists(PK)',
            }
        },
        {
            'Update': {
                'TableName': 'Inventory',
                'Key': {'PK': {'S': 'ITEM#42'}},
                'UpdateExpression': 'SET stock = stock - :d',
                'ExpressionAttributeValues': {':d': {'N': '1'}},
                'ConditionExpression': 'stock >= :d',
            }
        },
    ]
)
  • TransactWriteItems / TransactGetItems.
  • 2배 WCU/RCU 비용.
  • 실패 시 전체 롤백.

Conditional Writes

낙관적 동시성 제어. 조건 실패 시 ConditionalCheckFailedException.

table.update_item(
    Key={'PK': 'USER#42', 'SK': 'PROFILE'},
    UpdateExpression='SET version = :new, updatedAt = :ts',
    ConditionExpression='version = :cur',
    ExpressionAttributeValues={
        ':cur': 1,
        ':new': 2,
        ':ts': '2026-06-17T10:00:00Z',
    },
)

낙관적 잠금 패턴: version 속성으로 동시 업데이트 충돌 감지.

Access Pattern 설계 워크플로

flowchart TB
    A["1. Access pattern 정의"]
    B["2. Entity 목록 확인"]
    C["3. PK / SK 결정"]
    D["4. SK range query 검토"]
    E["5. GSI 필요 여부"]
    F["6. 단일 테이블 통합"]
    A --> B --> C --> D --> E --> F

entity 먼저 설계 후 access pattern 억지 = 나중에 전체 마이그레이션. 반드시 access pattern 우선 설계.

Global Tables

다중 리전 Active-Active 복제. 글로벌 레이턴시 최소화.

aws dynamodb create-global-table \
  --global-table-name Orders \
  --replication-group \
    RegionName=us-east-1 \
    RegionName=ap-northeast-2
  • 각 리전에서 읽기/쓰기 모두 가능.
  • eventual consistency (복제 지연 수백 ms).
  • 충돌 해결: last-writer-wins (timestamp 기반).

Backup / PITR

# On-demand 백업
aws dynamodb create-backup \
  --table-name Orders \
  --backup-name orders-backup-20260617

# PITR 활성화 (최대 35일 복구)
aws dynamodb update-continuous-backups \
  --table-name Orders \
  --point-in-time-recovery-specification \
    PointInTimeRecoveryEnabled=true

# 특정 시각으로 복구
aws dynamodb restore-table-to-point-in-time \
  --source-table-name Orders \
  --target-table-name Orders-Restored \
  --restore-date-time 2026-06-15T10:00:00Z

관련 위키

이 글의 용어 (6개)
[AWS] IAM: User, Role, Policy, STScloud
정의 IAM (Identity and Access Management) = AWS 의 권한 관리 전부. User, Group, Role, Policy 로 구성. "누가 어떤 리소…
[AWS] Lambda: 서버리스 함수, 트리거, 동시성cloud
정의 AWS Lambda = 서버리스 함수 실행. 이벤트 트리거 → 함수 실행 → 결과 / 비동기 처리. 서버 관리 0. 사용 상황 | 상황 | Lambda 적합성 | |---|…
[AWS] S3: object storage, storage classes, lifecyclecloud
정의 S3 = AWS 의 object storage. bucket + key + object. 11 9's durability (99.999999999%), 무한 확장. 2026…
[DB Internals] Redis 8 / Valkey 9: 라이센스 분기, 신 데이터 구조, 실전 운영database-internals
정의 Redis 는 in-memory key-value 데이터 구조 서버. 2009년 Salvatore Sanfilippo (antirez) 가 Lua Manuscripts 의 …
[DB] MongoDB: 문서 DB, WiredTiger, replica set, aggregationdatabase-internals
정의 MongoDB 는 BSON (binary JSON) 문서 기반 NoSQL DB. schema-less 라기보다 flexible schema. 2026 시점 Atlas (ma…
[DB] Sharding vs Partitioning: 수평 확장의 두 얼굴database-internals
정의 | | Partitioning | Sharding | |---|---|---| | 범위 | 한 DB 안 | 여러 DB 노드 | | 목적 | 큰 테이블 관리 | 수평 확장 (…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기