iT邦幫忙

2025 iThome 鐵人賽

DAY 22
0
Build on AWS

一步步帶你認識 Cloud Native —— 用AWS免費服務打造雲原生專案系列 第 22

Day22 DynamoDB 單表設計 (Single Table Design) | PK&SK、GSI、LSI 實現查詢邏輯

  • 分享至 

  • xImage
  •  

前言

上一篇文章,我們建立了一個簡單的 DynamoDB Table。今天要深入探討「單表設計 (Single Table Design)」,這是 DynamoDB 最常被討論也最容易誤解的主題。與其一開始就講抽象的 Query-centric vs Data-centric,我們先從大家熟悉的 SQL 關聯模型 開始。


SQL 的建模方式:一對多、多對多

  • 在 SQL 中,常見的例子:

    • 使用者 (Users) 與 專案 (Projects) → 一對多
    • 專案 (Projects) 與 任務 (Tasks) → 一對多
    • 使用者 (Users) 與 任務 (Tasks) → 多對多 (透過中介表 UserTasks)
  • 在 SQL 裡,要拿到「某個使用者的所有任務」:

    • 會需要 JOIN Users → UserTasks → Tasks
    • JOIN 是 SQL 很強的能力,但代價是效能開銷大。

https://ithelp.ithome.com.tw/upload/images/20250901/20178103UOd3arG7Xx.png

DynamoDB 拋棄 Join 是因為靠Foreign Key 將不同表格關聯起來會產生額外的計算成本,不便於水平擴展 (Scale out)
來自Creating a single-table design with Amazon DynamoDB


DynamoDB 的思維:單表設計

  • DynamoDB 不走 JOIN 的路線,而是走「事先設計好存取路徑」。
  • 這也是為什麼常有人說:DynamoDB 是 Query-centric (查詢導向),SQL 是 Data-centric (資料導向)
  • 我們把所有資料放在同一張表,靠 PK (Partition Key)SK (Sort Key) 來模擬關聯。

範例:Users + Projects + Tasks

PK SK Data
USER#123 PROFILE {name: Tom}
USER#123 PROJECT#A {title: X}
USER#123 PROJECT#B {title: Y}
PROJECT#A TASK#1 {desc: ...}
PROJECT#A TASK#2 {desc: ...}
  • 查詢某個使用者的專案? → Query PK=USER#123
  • 查詢某個專案的任務? → Query PK=PROJECT#A

這樣就省去了 JOIN。


進一步的工具:GSI & LSI

當業務需求變複雜,光靠 PK/SK 還不夠,我們會用到 索引

Local Secondary Index (LSI)

  • 跟主表 共享同一個 Partition Key,但可以用不同的 Sort Key 排序或查詢。
  • 適合「同一個使用者的多種排序方式」。

Global Secondary Index (GSI)

  • 可以用 全新的 PK & SK,不受限於主表的鍵設計。
  • 適合「跨 Partition 查詢」或「不同維度的存取需求」。

小整理表格

工具 特點 適合場景
PK (Partition Key) 水平切分資料,保證分散性 定位單一實體
SK (Sort Key) 在 Partition 裡排序與篩選 一對多關係
LSI 與主表共享 PK,不同 SK 單一實體的多種排序
GSI 全新 PK/SK,跨分區查詢 不同維度的查詢

實作章節:單表設計 + LSI/GSI 的應用

實作目標

  • 建立一個 DynamoDB 單表,模擬多人協作平台的核心資料:

接下來我們會設計一個 Table 並展示如何透過 PK、SK、LSI、GSI 實現不同查詢需求:

  • 查詢某使用者的專案與任務
  • 查詢某專案的所有任務
  • 查詢某使用者負責的所有任務(跨專案)

Table 設計

Partition Key / Sort Key

PK SK Data 說明
USER#123 PROFILE {name: Tom} 使用者基本資訊
USER#123 PROJECT#A {title: X} 使用者專案列表
USER#123 PROJECT#B {title: Y} 使用者專案列表
PROJECT#A TASK#1 {desc: ...} 專案任務列表
PROJECT#A TASK#2 {desc: ...} 專案任務列表

LSI(Local Secondary Index)範例

  • 功能:在相同 PK 下提供不同排序方式
  • 需求:查詢某使用者專案,依建立時間排序
  • 設計:
    • LSI PK = USER#123(與主表相同)
    • LSI SK = CREATED_AT#PROJECT#A
    • 查詢使用者專案時,可依時間排序而不影響原本主表 SK 排序

GSI(Global Secondary Index)範例

  • 功能:提供跨 Partition 的查詢能力
  • 需求:查詢所有某使用者負責的任務(跨不同專案)
  • 設計:
    • GSI PK = USER#123
    • GSI SK = TASK#1 或 TASK#2
  • 查詢時只需 Query GSI,即可取得使用者所有任務,無需掃描整個表

查詢邏輯示意

  1. 查詢使用者專案
    • Query 主表,PK = USER#123,SK begins_with "PROJECT#"
  2. 查詢專案任務
    • Query 主表,PK = PROJECT#A,SK begins_with "TASK#"
  3. 查詢使用者負責的任務
    • Query GSI,PK = USER#123

實作重點

  • 單表設計不只是「把所有資料丟同一張表」:
    • 需要考慮 Query 需求(Query-centric)
    • 合理使用 LSI/GSI 投影不同排序或查詢路徑
  • LSI 適合單 Partition 內多種排序需求
  • GSI 適合跨 Partition 的額外查詢需求

結語

今天展示了單表設計的概念 + LSI/GSI 的實際運用,下篇將進一步把完整業務邏輯整合進表格,形成可操作的多人協作平台資料模型


上一篇
Day21:DynamoDB | AWS No SQL 資料庫初探
下一篇
Day23 AWS DynamoDB 單表設計 ( Single Table Design )實戰 | 從業務邏輯開始設計高可擴展性的資料模型
系列文
一步步帶你認識 Cloud Native —— 用AWS免費服務打造雲原生專案24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言