DynamoDB 排序鍵策略:3 種模式及適用情境
一個 DynamoDB 主鍵是一個或兩個屬性:單獨的一個 ,或是一個 partition key 加上一個 sort key。partition key 決定哪個實體 partition 持有一個項目。
sort key 決定那個 partition 裡各項目的順序 — 而那份
順序正是讓 Query 強大的原因。
挑錯 sort key,你仍然寫得進資料,但你會失去範圍讀取、 排序,以及來自單一集合的好幾種存取模式。
從 SQL 過來,你會在事後伸手去用一個 ORDER BY 或一個次要索引。
在 DynamoDB 裡你事先就把順序烤進鍵裡,否則你就得不到它。
DynamoDB 的 sort key 是怎麼運作的?
一個 DynamoDB sort key 為一個 partition 裡的各項目排序,讓 Query 能做範圍讀取 — >=、between、begins_with — 而不是一次抓一個項目。字串 sort key 依 UTF-8 位元組排序(數字則依數值排序),所以要設計一個字串鍵(一個 ISO-8601 時間戳、一個補零的數字),讓位元組順序等於你想讀取的順序。
- sort key 是你的 partition 內索引。 它為磁碟上的 排序,
所以
Query能做範圍讀取(>=、between、begins_with),而不是 單一一個GetItem。 - 字串 sort key 依 UTF-8 位元組排序(數字依數值排序)。 設計一個
字串鍵,讓位元組順序等於你想讀取的順序 — 一個 ISO-8601
時間戳、一個補零的數字,絕不要一個原始 UUID 或
6/23/2026。 - 一個形狀良好的 sort key 服務多種存取模式。 一個
(
EVT#<timestamp>)同時是一個前綴和一個範圍 — 不需要 GSI。 - 方向是免費的。
ScanIndexForward = false以相同成本從最新的讀起; 別為了假造它而儲存反轉的時間戳。
為什麼 sort key 是那根槓桿
沒有 sort key,一個 partition 裡的每個項目就只能靠它完整的
主鍵定址 — 頂多是一個 GetItem。加上一個 sort key,DynamoDB 就會
把項目在 partition 內依它排序儲存,這就解鎖了 Query。
那意味著範圍條件(>=、between)、前綴比對(begins_with),
以及一個用來升冪或降冪讀取的 ScanIndexForward 旗標。
按照 AWS DynamoDB Developer Guide,所有共用一個 partition key 的項目 構成一個項目集合,在磁碟上依 sort key 排序。
所以 sort key 不只是第二個識別符。它是你在一個 partition 內 用來查詢的那個索引。
那份順序是在編碼過的 sort key 上的位元組順序:字串依 UTF-8 位元組比較,數字依數值比較。這一個事實驅動了底下幾乎每一個策略。
如果你要範圍查詢有意義,位元組順序就必須符合你想讀取的順序。
策略 1:讓 sort key 可排序
最常見的錯誤是一個沒有意義排序的 sort key。一個隨機 UUID 給你唯一性,但沒有任何有用的範圍查詢 — 「給我最後 20 筆」 變得不可能,因為位元組順序是任意的。
反過來,把你排序和篩選所依據的值編碼進 sort key 裡, 用一種位元組順序等於其邏輯順序的表示法。對時間戳而言,那 意味著一種可依字典序排序的格式:一個 ISO-8601 字串或一個補零的 epoch。
ISO-8601 的設計,就是要讓字串比較等於時間先後比較 —
正是一個範圍查詢所需要的。避開像 6/23/2026 這樣的格式;月份
一翻過去它們就排錯了。
如果你依數字排序(一個版本計數器、一個分數),使用 DynamoDB 原生的
Number 型別,而不是字串,這樣 42 就會排在 9 之後,而不是
在它之前。
如果一個數字必須存在一個複合字串 sort key 裡,把它補零到固定 寬度。
策略 2:用複合 sort key 表達階層
一個 sort key 可以用一個分隔符(最常見的是 #)串接各段來
編碼一個階層。接著一個 begins_with 條件就能選出一整個子樹:
| SK |
|---|
| EVENT#2026-06#01#login |
| EVENT#2026-06#03#export |
| EVENT#2026-07#02#login |
begins_with(SK, "EVENT#2026-06#") 只回傳六月的事件;更寬的
begins_with(SK, "EVENT#") 則回傳全部。
各段的排序是一個設計決定。由粗到細(年 → 月 → 日)讓 相關的項目保持相鄰,這樣一次範圍讀取仍是一個便宜的查詢,而不是 一次散落在 partition 各處的抓取。
策略 3:用 ScanIndexForward 控制方向
DynamoDB 以 sort-key 的升冪順序儲存項目,並預設以那個順序
讀取它們。要從最新讀起 — 一個活動動態的自然順序 — 就在
Query 上設 ScanIndexForward = false。
這是一個讀取時的旗標,不是一個結構決定:同一個集合以相同成本 服務兩個方向。別為了得到降冪讀取而反轉你的時間戳(儲存一個「反向 epoch」)。
一個項目集合,以升冪順序儲存一次,兩個方向皆可讀取:
同樣的項目、同樣的 partition、同樣的成本 — 只有讀取方向不同。
實作範例:一個以行為者為範圍的稽核日誌
假設你在一個 SaaS 產品裡記錄由行為者 — 使用者、服務、API 金鑰 — 產生的帶時間戳事件,而你有兩種讀取:
- 某個行為者的活動串流,最新的事件在最前面。
- 某個行為者在一個時間窗內的事件(例如「兩次部署之間的 一切」),供調查使用。
兩種讀取都以單一行為者為範圍,所以行為者是 partition key,而 事件時間是 sort key。使用通用的鍵名,讓同一個表格日後也能容納其他 實體:
| PK | SK | attributes |
|---|---|---|
| ACTOR#u_8814 | EVT#2026-06-23T09:12:04Z | action=login, ip, ua |
| ACTOR#u_8814 | EVT#2026-06-23T14:05:11Z | action=export, target |
| ACTOR#u_8814 | EVT#2026-06-24T08:40:55Z | action=login, ip, ua |
| ACTOR#svc_billing | EVT#2026-06-23T00:00:00Z | action=invoice.run |
EVT# 前綴加上一個 ISO-8601 時間戳,就給出一個可排序的 sort key。讀取 1 是
Query PK = "ACTOR#u_8814",配上 ScanIndexForward = false 讓最新的在最前。讀取
2 則用一個 sort key 上的 between 條件在同一個 partition 內縮小範圍:
Query
PK = "ACTOR#u_8814"
AND SK BETWEEN "EVT#2026-06-23T00:00:00Z"
AND "EVT#2026-06-23T23:59:59Z"
一個集合、兩種存取模式、不需要 GSI — 因為這個 sort key 既是一個前綴
(EVT#)又是一個範圍(那個時間戳)。降冪讀取與時間窗讀取是相同順序
下的相同項目;只有參數不同。
親手建構那個鍵條件時,很容易在 between 的邊界上出錯,或在
屬性名稱上搞砸保留字的轉義。
DynamoDB Expression Builder
會為一個 begins_with 或 between 的 sort-key 條件產生
KeyConditionExpression、ExpressionAttributeNames 與
ExpressionAttributeValues。
把它直接複製進你的 SDK 呼叫,而不是在執行期除錯轉義問題。
在 DynoTable 中操作
設計一個 sort key 是反覆的:寫幾個有代表性的項目、跑那個範圍 查詢,並檢查那些列以你預期的順序回來。在一個 GUI 裡對一個 上線表格做這件事,勝過在程式碼裡來回折騰。

翻動排序方向、收緊 between 的邊界,親眼看著回傳的集合改變,
一行程式碼都不用寫 — 在你把一個 sort-key 設計提交之前,這是確認它的
最快方法。
陷阱與後續步驟
- sort key 在一個 partition 內必須唯一。 如果兩個事件可能共用一個 時間戳,就在 sort key 上附加一個消歧符(一個序號或短 id), 讓這個複合鍵保持唯一。
- 一個熱點 partition 無法靠排序繞過。 如果某個行為者產生的事件 遠多於其他人,sort key 救不了你 — 你需要一個能把負載 攤開的 partition-key 設計。見 single-table design。
- 第二種排序順序需要第二個索引。 基礎表格的 sort key 給你 一種排序。要以不同方式(比如依事件類型)為相同項目排序,就 加一個帶不同 sort key 的 GSI — 並權衡 local 與 global secondary index 的取捨。
- 別為了「之後再排序」而伸手去用
Scan。 在一次Scan之後於用戶端 排序,會讀取整個表格並丟掉順序;那就是 Scan 地雷。改把順序推進 sort key 裡。
一旦鍵條件對了,就試用 DynoTable 來為這個集合建模、 並排跑升冪與降冪查詢,並在你的 sort-key 策略上線之前,對著真實資料 驗證它。


