DynamoDB 與資料模型
Vibe Prompt
「幫我設計 DynamoDB 表格儲存電商訂單資料:支援依使用者查詢、依日期查詢、依狀態查詢。」
表格設計
Orders Table:
Partition Key: user_id (String)
Sort Key: order_id (String)
GSI 1: status-created_at-index
Partition Key: status (String)
Sort Key: created_at (String)
GSI 2: created_at-index
Partition Key: created_at (String)
CRUD 操作
# 查詢使用者訂單
response = table.query(
KeyConditionExpression=Key('user_id').eq('user_123')
)
# 依狀態查詢(使用 GSI)
response = table.query(
IndexName='status-created_at-index',
KeyConditionExpression=Key('status').eq('pending')
)
# 寫入
response = table.put_item(Item={
'user_id': 'user_123',
'order_id': 'order_456',
'amount': 99.99,
'status': 'pending',
'created_at': '2025-06-30T10:00:00Z'
})
# 更新
response = table.update_item(
Key={'user_id': 'user_123', 'order_id': 'order_456'},
UpdateExpression='SET #st = :st',
ExpressionAttributeNames={'#st': 'status'},
ExpressionAttributeValues={':st': 'completed'}
)
最佳實踐
- ✅ 避免 Hot Partition:Partition Key 要有足夠的區分度
- ✅ 使用 Pay Per Request:流量不穩定時最省錢
- ✅ 設定 TTL:自動過期舊資料
- ✅ 搭配 DAX:提升讀取效能
關鍵要點
DynamoDB 設計黃金法則
| 法則 | 說明 | |------|------| | 單一表格設計 | 一個 Table 放所有資料,用 Sort Key 區分資料類型 | | PK = Entity ID | 分割區鍵決定資料分布,避免 Hot Partition | | SK = 時間戳 + 類型 | 排序鍵支援範圍查詢與排序 | | 避免 Scan | Query 才是 DynamoDB 的正確用法 | | GSI 適度使用 | 每張表最多 20 個 GSI,太多會增加成本 |
存取模式範例
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('myapp-prod')
# 高效 Query(透過 PK + SK)
response = table.query(
KeyConditionExpression=Key('pk').eq('user#123') &
Key('sk').begins_with('order#')
)
# ❌ 避免 Scan(全表掃描,昂貴)
# ✅ 使用 GSI + Query 替代
# 批次寫入
with table.batch_writer() as batch:
for i in range(100):
batch.put_item(Item={'pk': f'item#{i}', 'sk': 'metadata', 'data': f'value{i}'})
RCU / WCU 計算
- 1 RCU = 1 次 Strongly Consistent 讀取(4KB)/ 2 次 Eventually Consistent(8KB)
- 1 WCU = 1 次写入(1KB)
DynamoDB 除錯筆記:Hot Partition 的真實案例
假設你的電商訂單表 Partition Key 是 status(pending、shipped、completed)。當雙十一活動大量訂單湧入時,所有 pending 狀態的訂單都寫到同一個 Partition——你創造了一個 Hot Partition。
# ❌ 錯誤設計:低區分度的 Partition Key
# 所有 pending 訂單擠在同一個 Partition,效能卡在 3000 RCU / 1000 WCU
table.put_item(Item={
'PK': 'pending', # ❌ 只有少數幾種值
'SK': 'ORDER#2025-11-11#001',
'user_id': 'user001',
'amount': 599
})
# ✅ 正確設計:高區分度的 Partition Key
# 每個使用者的訂單分散在不同 Partition,水平擴展無上限
table.put_item(Item={
'PK': 'USER#user001', # ✅ 每個使用者不同 PK
'SK': 'ORDER#2025-11-11#001',
'status': 'pending', # 狀態放在一般屬性,用 GSI 查詢
'amount': 599
})
這個錯誤在開發環境永遠不會發現——直到上線被流量沖垮。DynamoDB 的設計核心是「先想好查詢模式,再設計表格」。
為什麼要學 DynamoDB?
在 Serverless 世界裡,DynamoDB 是最常用的資料儲存層。它沒有 SQL 的 JOIN、沒有自動遞增 ID、沒有 Foreign Key——這些「限制」其實是刻意設計的,目的是逼迫你用存取模式主導設計(Access Pattern Driven Design)。學好 DynamoDB 等於學會了 NoSQL 資料建模的思考方式。\n\n### 如何學好 DynamoDB?
| 學習階段 | 重點 | 實作練習 |\n|:-------|:----|:--------|\n| 基礎 | PK/SK 設計、Query vs Scan | 建立一個簡單的 User Table |\n| 進階 | Single Table Design、GSI/LSI | 設計電商系統(使用者+訂單+商品) |\n| 實戰 | Hot Partition 排查、DAX 快取 | 壓力測試 + CloudWatch 監控 |\n| 優化 | RCU/WCU 計算、Auto Scaling | 成本優化報告 |\n\n### 接下來學什麼
本章建立了 DynamoDB 單表設計的基礎觀念。下一章 DynamoDB 與 EventBridge 將教你:當資料變更時,如何用 DynamoDB Streams 觸發後續事件,以及如何用 EventBridge 做跨服務的非同步通訊——這是你從「單體資料庫」思維進化到「事件驅動架構」的關鍵一步。"