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 是 statuspendingshippedcompleted)。當雙十一活動大量訂單湧入時,所有 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 做跨服務的非同步通訊——這是你從「單體資料庫」思維進化到「事件驅動架構」的關鍵一步。"

會員專屬免費教學

本章節為註冊會員專屬的免費開放內容!請先登入或註冊會員,即可立即解鎖閱讀。

立即登入 / 註冊