快速理解 DynamoDB 的 Primary Key
在任何資料庫中,Primary Key(主鍵)都是一個獨一無二的識別符,用來標識資料表中的每一筆記錄。在關聯式資料庫(例如 MySQL 或 PostgreSQL)中,主鍵通常是一個單獨的欄位(像是 ID),但在 DynamoDB 這樣的 NoSQL 鍵值儲存系統中,主鍵的概念稍微不同,且更靈活。
DynamoDB 的主鍵有兩種類型:
單一主鍵,只使用 Partition Key(分區鍵)
複合主鍵,Partition Key 和 Sort Key(排序鍵)組成
這兩種類型決定了資料如何儲存、分割,以及如何被快速查詢。讓我們深入這兩者的運作方式。
兩種主鍵
單一主鍵
單一主鍵只使用 Partition Key,Partition Key 是 DynamoDB 的基礎主鍵類型。如果你的資料表只有 Partition Key,它就像是你資料的「門牌號碼」。
由於 DynamoDB 是分散式資料庫,資料會被分割到多個伺服器上以實現高可用性和擴展性。Partition Key 的值決定了資料的「家」在哪個分區,透過內部的雜湊函數(Hash Function),決定這筆資料會被儲存在哪個實體分區(Partition)。舉個例子:
假設你有一個 Users 資料表,Partition Key 是 UserID。當你儲存 UserID = “user123” 的資料時,DynamoDB 會把 “user123” 丟進雜湊函數,算出一個分區編號(例如 Partition 5),然後把資料丟去那裡。
複合主鍵
Partition Key + Sort Key。這種設計讓 DynamoDB 不只是一個簡單的鍵值儲存,還能支援範圍查詢(Range Query)。
Sort Key(排序鍵)是 Partition Key 的「副手」。在同一個 Partition Key 下,Sort Key 會決定資料的排序順序。想像 Partition Key 是「書架編號」,告訴你去哪個書架找,而 Sort Key 是「書的排序號」,讓你在書架上按順序找到書。
沒有這些「編號」,你就只能一本本翻閱整個圖書館。
Primary Key 在 DynamoDB 中的重要性
為什麼說理解 Primary Key 是理解 DynamoDB 的關鍵?因為它直接影響:
-
資料儲存:Partition Key 決定資料如何分散到多個分區,影響效能和擴展性。
-
查詢效率:DynamoDB 的查詢基本上都依賴主鍵(除非用索引,但那是另一個話題)。沒有主鍵,你無法快速找到資料。
-
成本:熱點問題或不當的主鍵設計會導致效能瓶頸,增加讀寫容量單位的消耗。
把 GSI (Global Secondary Index) 當成是另一種類型的 Primary Key
由於 Primary Key 就是你的搜尋或查詢方式,它是一種資料的呈現面向,但資料可能需要呈現的維度通常是多維的,例如研討會是以學員報到為核心,查詢時以找到學員這個人為目標。但如果研討會供餐,就需要從另一個維度來思考如何取得吃什麼東西的資料集合。
由於 Primary key 是以學員為維度,無法處理吃什麼這樣的維度,我們就可以透過 GSI 來處理這個查詢。
由於 GSI 可以有自己的分區鍵和排序鍵組合,因此在設計與應用上的邏輯,基本與 Primary key 一樣。
但一如 Primary key,透過 overloading 的方式來使用 PK 與 SK,GSI 在設計上也要考慮這個技巧,避免一個查詢維度就使用一個 GSI,既增加成本,也造成維護上的麻煩,更有可能隨著時間增加遇到 GSI 使用的上限(一張表 20 個)。
從關聯式思維轉換
對習慣了關聯式資料庫的開發者來說,DynamoDB 的主鍵設計需要思維轉換:
-
SQL:圍繞表關係和JOIN操作設計,WHERE 查詢減少了對資料存取的事先思考
-
DynamoDB:圍繞訪問模式(access patterns)設計
最重要的問題從「我的資料如何組織?」變成「我需要如何查詢這些資料?」,而且必須在資料表設計階段就決定好。
設計主鍵的建議
從查詢需求反推主鍵
先問自己:應用程式最常查什麼?單一值的查詢還是範圍查詢?
例如,單一值查詢(像統編)用 Partition Key 就夠;範圍查詢(像訂單日期)加個 Sort Key。
避免熱點
不要用低基數(low cardinality)的值當 Partition Key,例如 Status = “Active”,因為大部分資料會擠在同一個分區。
可以考慮把低基數值加到 Sort Key,或者用隨機後綴(例如 UserID#001)來分散資料。
掌握 Overloading 的技巧
Overloading 指的是在 Primary Key 中「塞進」多種資料類型,讓主鍵屬性承載多重實體。這樣做的目的是:
-
減少對 Secondary Index 的依賴:避免額外的索引成本和複雜性。
-
支援多種查詢模式:用同一個資料表滿足不同的存取需求。
-
提升靈活性:讓主鍵適應應用程式的動態需求。
簡單來說,Overloading 就像是把多個「標籤」壓縮到同一個鍵裡,讓 DynamoDB 的查詢能力在有限結構下發揮最大效用。
把主鍵和資料的運用徹底切分
我們可以把一筆 item 拆成兩個部分,一部分是主鍵,一部分是資料,並且當作是不同的功能群組。
主鍵存在的目的是為了代表一組資料,以及操作該筆資料,以及透過 partition key 和 sort key 來查詢並產出一組 item collection。以房子來說,它就是門牌號碼,指出自己所在的位置,大多數的情況,它應該是不可變動的性質。
資料則是我們在應用程式中實際上要呈現的資訊,同樣的比喻,它是房子裡的房客,有可能搬出搬入,成員也有可能會變化,它是屬於可變動的性質。
很多時候,PK 與 SK 鍵可能會與資料中需要的欄位相同,例如我們 PK 鍵使用 email,或許就會覺得那我取得 PK 鍵就知道 email 了,不需要再資料欄位中多放一個 email 屬性,也可以節省一些資料空間。
但千萬不要這麼做,隨著資料成長,很多時候資料會有異動或是需要增加索引的情境,這時如果缺少資料的欄位,就會少了很大的彈性再做運用。對於需要 pre-join 來應付各種查詢情境而言,這樣的預留設計非常的重要。
因此在開發時,我們也會加上一些前綴詞,讓 key 的值徹底的與資料長得不同。
但更重要的是,在心裡把主鍵和資料當成兩邊互相看不到對方,將他們分別開來,key 是 key,data 是 data,在心裡默念一百遍。
使用主鍵的注意事項
-
新增資料時如果沒有提供 Primary Key 會失敗
-
新增資料時如果使用已經存在的 Primary Key ,原來的資料會被整個覆蓋,舊資料如果有不同的屬性也都會丟失。
-
Primary Key 不能修改
-
只有 Primary Key 可以使用 item base 的操作(針對單筆資料的新增、更新、刪除),GSI 雖然類型 Primary Key,但只能使用 query,scan 語法
結論
主鍵設計是 DynamoDB 開發的基石。好的主鍵設計使你的應用高效、可擴展,而糟糕的設計則可能導致性能問題和更高的成本。在設計應用時,首先明確你的資料訪問模式,然後據此設計你的主鍵結構。
記住,在 DynamoDB 中,主鍵不僅是識別數據的方式,更是檢索和資料數據的核心策略。