# AWS - DynamoDB GSI VS LSI


# DynamoDB GSI

DynamoDB Global Secondary Index (GSI) 在 DynamoDB 上為一張 Table 建立的 『跨分區、可獨立查詢鍵』索引,允許用不同的 Partition Key/Sort Key 查詢資料,並有自己儲存與吞吐特性 (通常為 eventually consistent)


# 基本概念

  • GSI 有自己的 Partition Key 與 Optional 的 Sort Key,可以與 DynamoDB Table 的不同
  • GSI 儲存的是表中被投影 (projected) 的屬性的一份副本 (或不份副本)
  • GSI 是跨分區的 (global),適合跨整個表做查詢,而不只局限於原主鍵的 partition

# 寫入與一致性行為

  • 寫入到主表時,DynamoDB 會同時『異步』將變更資料複製到相關 GSI (因此 GSI 查詢通常是 eventually consistent)
  • 這代表:剛寫入主表後立即查 GSI 可能看不到最新資料
  • 使用 DynamoDB Transactions (TransactWrite) 可保證多項目一致性,交易也會處理 GSI 的更新 (交易內的各項變更原子套用)
  • 如果項目在 GSI Index Key 屬性為 null -> 該項目 不會寫入該 GSI (形成 sparse index,可用於解省空間或特定過濾)

# 投影 (Projection Types)

  • KEYS_ONLY: 只儲存主鍵與 GSI Key (最省空間)
  • INCLUDE: 儲存文指定的附加屬性 (自訂清單)
  • ALL: 儲存整個 item 的副本 (最耗空間、讀取最快)

# 容量與成本 (讀寫與儲存)

  • Provisioned mode: GSI 可有自己 provisioned RCU/WCU (過去寫入會消耗 GSI 的 WCU)
  • On-Demand: 自動按需計費
  • 寫入成本:每次寫主表若影響 GSI,會額外產生 GSI 的寫入消耗 (因此高寫量下成本會放大)
  • 儲存成本: GSI 儲存被投影的資料,會產生成本 (ALL 投影最貴)

# 性能 / 熱點問題

  • GSI 會分散到多 Parition, 若 GSI Parition key 分佈不均會出現 hot parition (寫入瓶頸)
  • 高寫入熱點常用 write sharding (在 index key 加隨機 prefix) 解決,並在讀取端再合併
  • GSI 更新的延遲受 table 的寫入速率與分區分佈影響,大量突發寫入可能造成 GSI 更新 Cache 或被 throttle

# 使用限制與操作行為

  • 可以在表建立後新增或刪除 GSI(建立時會做 Backfill,刪除會移除索引資料)。
  • 新增 GSI 時會觸發 後台 backfill(掃描表並建立索引),這期間可能影響表的吞吐。
  • GSI 的項目數量與大小會計入儲存限制;單項目大小限制仍適用(400 KB)。
  • 每個 region /account 有 GSI 數量上限(可調用限額提升)。

# 設計建議(常用 patterns)

  • 為每個 access pattern 建一個 GSI(單表設計的核心)。
  • 使用 sparse GSI:只有當特定屬性存在才會被索引(用於某些狀態或類別的查詢)。
  • 選擇精簡投影(INCLUDE / KEYS_ONLY)以節省儲存和寫入成本。
  • 避免使用高基數單一 key 導致 hotspot:使用複合 key 或 sharding。
  • 在高寫入場景,考慮 on-demand 或適當 provisioned + auto-scaling。

# 監控與排錯重點(CloudWatch 指標)

  • 監控:ConsumedWriteCapacityUnits、ConsumedReadCapacityUnits(GSI 層面)
  • 錯誤 / 瓶頸:ThrottledRequests、ProvisionedWriteCapacityExceeded(若 provisioned)
  • 延遲觀察:查詢結果不一致 → 檢查表到 GSI 的同步延遲與 backfill 狀態。
  • 若查不到資料:檢查該 item 是否有 GSI key 屬性(若沒有,項目不會出現在 GSI)。

# 成本 / 效能實務小技巧

  • 減少 GSI 的投影屬性以降低儲存與寫操作。
  • 把 write-heavy attributes 放在主表且只在必要時投影到 GSI。
  • 使用 adaptive capacity /auto scaling 並設 alert 以避免 throttle。
  • 大量新增 GSI 時,分批啟用或在低流量時新增以減少 backfill 影響。

# 備註

  • GSI 可後加(vs LSI 必須建表時定義) → 考試常考差別題。
  • GSI 有自己的吞吐與儲存成本 → 寫入會消耗主表 + GSI 的寫入單位。
  • 若索引鍵屬性不存在,該 item 不會出現在 GSI(sparse index)。

# GSI VS LSI 表格整理

比較項目 GSI (Global Secondary Index) LSI (Local Secondary Index)
Partition Key 可以不同於主表 必須相同於主表
Sort Key 可不同 必須不同於主表 SK
建立時間 ✅ 隨時可新增 / 刪除(建後會 backfill) ❌ 必須在建表時定義
容量模型 獨立 RCU/WCU(Provisioned) 共用主表吞吐量
儲存空間 ✅ 有自己儲存(多一份 copy) ❌ 共用主表 storage
一致性 Eventually consistent(預設) ✅ 可支援 Strong Consistent Read
Query 範圍 跨整表(Global) 限同一 partition(Local)
Sparse Index 支援 ✅ ✔ ✅ ✔
成本影響 雙倍寫入成本(含儲存費) ✅ 寫入只算主表成本
Hot partition 風險 高(若 PK 分佈不均) 與主表 PK 相同(風險相同)
最大數量 20 /table(上限可調) 最大 5 /table(固定)
典型用途 非主鍵屬性查詢 / 多 access patterns 單 PK 多排序條件查詢