中階閱讀時間 2 分鐘

DynamoDB 的單一表格設計

從 SQL 過來的直覺是每個實體一張表:customersordersorder_items。在 DynamoDB 中那個直覺通常是錯的。一張儲存每一種實體、以重載的鍵前綴來區分的單一表格,能讓你在一次 Query 中取得一個父項與它的所有子項 — 沒有 join,沒有 N+1。

什麼是 DynamoDB 的單一表格設計?

單一表格設計把每一種實體 — customer、order、order item — 都存進一張 DynamoDB 表格中,以重載的與排序索引鍵前綴來區分。因為鍵是圍繞你的存取模式而非你的實體來設計,一個父項與它的所有子項就住在同一個中,並在單一個 Query 中一起回傳 — 沒有 join,沒有 N+1 讀取。

核心概念

挑選通用的鍵名稱(PKSK),並把實體型別編碼進值裡:

PKSKattributes
CUSTOMER#42PROFILEname, email, plan
CUSTOMER#42ORDER#2026-001total, status
CUSTOMER#42ORDER#2026-002total, status

現在一個 Query PK = "CUSTOMER#42" 會在單一個計費讀取中回傳個人資料以及每一筆訂單。SK begins_with "ORDER#" 則把範圍縮小到只有訂單。

視覺上,重載的項目會堆疊在單一個之下,成為單一個

Partition: CUSTOMER#42SK: PROFILESK: ORDER#2026-001SK: ORDER#2026-002一個 Query

一次讀取這個分割區,就把該顧客與每一筆訂單一起交還給你。

重載的 GSI

同樣的手法也適用於索引。在項目上放一個通用的 GSI1PKGSI1SK,單一個 就能依每個項目寫進那些屬性的內容服務多種存取模式:

PKSKGSI1PKGSI1SK
ORDER#001METADATASTATUS#OPEN2026-01-04
ORDER#002METADATASTATUS#OPEN2026-01-05

現在 Query GSI1 WHERE GSI1PK = "STATUS#OPEN" 會依日期列出未結訂單 — 這是基礎表格無法回答的模式。另一種實體可以用它自己的含意重用 GSI1(例如 CATEGORY#books)。一個索引,多種查詢。

多對多:鄰接串列

對於各種關係(一個使用者屬於多個團隊,一個團隊有多個使用者),把這條邊寫兩次、把 id 對調:PK=USER#1, SK=TEAM#9 以及 PK=TEAM#9, SK=USER#1。查詢任一側都會列出另一側 — 這是 DynamoDB 對 join 表的替代做法。

何時不該用單一表格

它並非免費。一張重載的表格更難推敲、更難演進,而且對分析不友善。如果你的存取模式真的未知或不斷改變,或資料主要是分析性的,那麼分開的表格(或另一種儲存)可能才是比較明智的選擇。單一表格在模式已知且高流量時才會勝出。

錯誤形狀的成本

把資料建模成分開的表格,會迫使你用 Scan 或用戶端 join 來重新組合出一個顧客,而那正是 Scan 陷阱。先建模存取模式,再設計鍵,讓每一種模式都成為一個 Query。(至於那個你從未建模到的臨機跨實體問題,DynoTable 的 SQL Workbench 能在用戶端執行 JOIN——探索不必等一次重新建模。)

用免費的單一資料表設計工具勾勒設計本身——它會把你的存取模式清單變成 PK/SK/GSI 規劃,附上範例項目與成本提示。 用項目大小與容量計算機估算這些項目每次讀取的成本,並試用 DynoTable,即可瀏覽一個單一表格 schema,並排看到那些重載的集合。

已更新

互動式地試用這個設計

在免費的 DynamoDB 單一資料表設計工具中勾勒你的實體與存取模式 — 它會建議 PK/SK 鍵範本、預覽項目集合,並顯示哪些模式需要 GSI。

開啟單一資料表設計工具