DynamoDB 複合主鍵
複合主鍵是兩個屬性:一個分割鍵和一個排序鍵。分割鍵決定一個項目住在哪裡;排序鍵把那個分割裡的項目排序。
從 SQL 過來,與其把它想成一個唯一的 id 欄,不如把它想成 GROUP BY partition, ORDER BY sort 直接烤進了表本身。
什麼是 DynamoDB 複合主鍵?
DynamoDB 複合主鍵結合兩個屬性:一個分割鍵和一個排序鍵。分割鍵決定一個項目存放在哪個實體分割;排序鍵把那個分割裡的項目排序。兩者合起來構成項目的唯一身分,並讓單一次 Query 回傳一個排好序的範圍,而不是單一個項目。
- 兩個部分,兩個職責。 分割鍵把項目導向一個實體分割;排序鍵把共用那個分割鍵的每一個項目排序。
- 唯一性是那一對。 只要排序鍵不同,兩個項目就能共用一個分割鍵值——一個分割就是這樣裝下許多列。
- 排序鍵才是整個重點。 它讓一次
Query回傳一個範圍(>=、between、begins_with)而不是一個項目,沒有Scan。 - 鍵必須是純量。 分割鍵和排序鍵只能是字串、數字或二進位——沒有映射、沒有列表(AWS 文件)。
簡單鍵 vs 複合鍵
簡單主鍵只是一個分割鍵。它唯一地識別一個項目,你用 GetItem 把它讀回來。就這樣——沒有範圍讀取,沒有「給我最新的 N 個」。
複合鍵加上排序鍵,而那單一個加法,就是讓 DynamoDB 感覺像個資料庫、而不是個雜湊表的關鍵。
| 簡單鍵 | 複合鍵 | |
|---|---|---|
| 屬性 | 只有分割鍵 | 分割鍵 + 排序鍵 |
| 唯一性 | 分割鍵值 | 那一對值 |
| 每分割多個項目 | 否 | 是 |
Query 一個範圍 | 否(只能 GetItem) | 是(begins_with、between、>) |
| 天然合適 | 依 id 查找 | 時間序列、一對多、歷史 |
建模一張感測器讀數表
假設你從一隊現場感測器蒐集溫度樣本。存取模式是「取得某個裝置在某個時間窗內的讀數,最新優先」。那是教科書般的複合鍵。
用裝置 id 當分割鍵,讀數時間戳當排序鍵:
| deviceId | readingTs | tempC | humidity |
|---|---|---|---|
| DEV#a1b2 | 2026-06-23T08:00:00Z | 21.4 | 48 |
| DEV#a1b2 | 2026-06-23T08:05:00Z | 21.7 | 47 |
| DEV#a1b2 | 2026-06-23T08:10:00Z | 22.1 | 46 |
| DEV#c9d8 | 2026-06-23T08:00:00Z | 19.8 | 55 |
全部三筆 DEV#a1b2 讀數落在同一個分割,實體上儲存在一起,並依 readingTs 排序。
AWS 把分割鍵稱為雜湊屬性(hash attribute),把排序鍵稱為範圍屬性(range attribute)——排序鍵是一個你能在其內掃描的範圍(AWS 文件)。
以下是這些項目如何在每個分割鍵之下塌縮成一個項目集合:
針對分割鍵的一次 Query 讀出那個裝置的每一筆讀數,而且已經按時間戳排好——不必在用戶端排序,不必第二趟往返。
查詢範圍,別掃描它
因為 readingTs 是一個 ISO-8601 字串,它按字典序排序的方式,跟它按時序排序的方式相同。所以一次時間窗讀取是一個鍵條件範圍,不是一個過濾:
Query
deviceId = "DEV#a1b2"
readingTs BETWEEN "2026-06-23T08:00:00Z" AND "2026-06-23T08:10:00Z"
那是一個 KeyConditionExpression——它在 DynamoDB 回傳資料之前就把讀取縮小,所以你只為窗內的項目付費。一個 FilterExpression 在讀取之後才執行,並為它掃過的一切向你收費;那就是迷你版的 Scan 地雷。
那個表達式本身,帶著佔位符與帶類型的值,手寫起來很麻煩。用 DynamoDB Expression Builder 視覺化地建好它,並把確切的 KeyConditionExpression 複製進你的 SDK 呼叫。
刻意地設計排序鍵
排序鍵不是免費的中介資料——它是範圍讀取的唯一槓桿,所以要依你的查詢來塑形它。
- 用一個可排序的時間戳。 ISO-8601 字串或補零的 epoch 數字會正確排序;原始的本地化日期不會。
- 為一對多超載加上前綴。 一個像
READING#2026-06-23T08:00:00Z的排序鍵,讓你在一個分割之下混放實體類型,並用begins_with切片。那是通往單表設計的接縫。 - 把高基數的維度放進分割鍵。 感測器 id 有數千個值,所以它把寫入均勻分散。一個低基數的分割鍵(比如
region)會造出一個熱分割。
複合鍵什麼時候會咬你
它是一個承諾,不是一個方便。陷阱是:你挑了一個分割鍵、上線了,然後發現一個需要不同分組的存取模式——「整隊裡所有高於 30°C 的讀數」。
基礎表回答不了那個;分割鍵是固定的。你的選項是一個帶不同鍵的全域次要索引,或重建結構。
在你提交鍵綱要之前,列舉你的讀取。改變一個主鍵意味著一次表遷移,不是一個 ALTER TABLE。
下一步
複合鍵是項目集合、一對多關係和大多數有用的索引設計底下的根基——接著讀單表設計和 GSI 與 LSI,看看它們通往何處。
在 DynamoDB Expression Builder 裡草擬你的 KeyConditionExpression,然後試用 DynoTable,去瀏覽你真實的分割,看著排序順序對著你自己的表對齊。