# 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 多排序條件查詢 |