洛基一早搭車前往大師家,看看手錶,還有 10 分鐘才到約定時間,於是他提前下車,散步過去。
地球的樣子跟他的母星沒有差太多,但天空更明亮一些,也更溫暖一點。
昨天聽完 DynamoDB 的介紹,他知道這是一個完全不同於他過去經驗的資料庫,也許他過去的經驗完全都派不上用場,一方面對於能向大師學習這門技術感到興奮,但也擔心自己真的有辦法在一個月內學會它。
「來都來了」這是他到地球後學到的一句話,對於遇到的狀況就去接受它。他覺得這樣想很好。
到門口剩一分鐘,他默默在心裡倒數計時,在最後一秒時按下門鈴。
進到茶室,洛基發現他的桌上有個白色陶磁圓筒,裡面有幾支竹筷。
「我們今天先從這個筷子小遊戲開始。」大師微笑地說。
在洛基坐定之後,諾斯克大師幫他倒了一杯茶,「今天是薄荷茶,這種天氣來一點,非常消暑氣。」
洛基邊喝茶邊盯著筷子,想著這會是怎麼樣的遊戲?
「遊戲非常簡單,圓筒中有9支竹筷,等等 Hippo 會隨機說出一顏色,你要找到筷身中寫有那個顏色的筷子。不過有一個限制,一次只有一支筷子能離開圓筒,這樣有沒有問題?」
「報告沒有問題!」洛基軍人式的反射回應。
於是遊戲開始,Hippo 喊出第一個顏色是「紅色」。
圓筒筒身不大,所以洛基只能一支一支抽出來看,抽到第3支後,剛好是紅色。Hippo 回答:「使用時間3秒」
「黑色」,語音一落,洛基樂於挑戰的本性被點醒,加速抽換筷子,不過有時會重複抽到,因此用了 10 次才抽到。這次花了 8 秒的時間。
「紫色」,這次洛基學到經驗,把抽過的筷子用另一個手指扣住,另一手抽新的筷子,這次花了 5 秒。
又試了幾次,有第一次就抽中的,也有運氣不好幾乎快抽完才抽中,不過經過他的優化,後來都在 6 秒內完成。
大師說:「邊玩邊優化,進步的很快,時間控制得不錯。」
洛基面對稱讚一向不知道該怎麼回應,只能硬硬地回答:「謝謝大師」。
「那麼我們就進入下一關」大師將圓筒收回,拿出一個一樣的白色磁筒,只是這次的筷子不一樣,露出瓶身之外的筷頭都上了不同的顏色。
Hippo 喊出「黃色」,洛基帶著疑惑地抽出黃色筷頭的筷子,果然筷身上寫著「黃色」。
「使用時間1秒」。
接下來幾次都一樣,筷頭上的顏色與筷身上寫的文字顏色是一致的,所以洛基都可以一次就取出正確的筷子,使用的時間都是1秒。
大師說:「第一次你做了一些優化,但速度時快時慢。第二次卻怎麼樣都是一秒,你覺得原因是什麼?」
洛基回答:「因為我看到筷子上面的顏色就知道要選哪一個了,不需要把它抽出來檢查文字,所以一次就可以知道。」
大師說:「沒錯,我們只需要知道上面的顏色,不用管下面的內容。這個顏色就相當於 DynamoDB 的主鍵,主鍵對於 DynamoDB 這樣的 key-value 的資料庫,就是我們用來找 value 的 key,而且因為 key 不能重複,就像每個顏色都不一樣,所以你可以一次就找到對的資料,速度也因此變得很快而且固定。」
「接下來讓我們來進行第三個筷子遊戲」只見大師拿出另一組白色磁筒,這次的筷子又不同,有別於前一組的筷頭是單色,這次的筷頭有上下雙層顏色,數量也比較多,但上層的顏色只有紅、綠、藍 3 種,下層的顏色則和之前一樣有9種。
「這次的規則有點不同,如果 Hippo 指定的是雙色,你還是只能一次抽出一支,但如果指定的是單色,你可以把所有同顏色的一次抽於來再找目標。」
Hippo 說「紅綠」,洛基一樣馬上抽出來。
「綠色,編號3」,洛基將所有的綠色抽出來,在一支「綠黃」的筷子上找到上面寫「綠黃 No 3」。
「藍色,編號8」,洛基一樣將所有的藍色抽出來,在一支「藍黑」的筷子上找到「藍黃 No 8」。
這時洛基忽然想到一件事,覺得很有可能是這樣的設計。
「紅色,編號7」,這時洛基直接將紅紫色那支抽出來,果然上面是寫著「紅紫 No 7」。
大師讚許地看著洛基:「看起來你已經抓到遊戲的重點了。」
洛基回答:「顏色的有序性。紅橙黃綠藍靛紫是一般的定序,也就是分別對應1到7,而黑色是8號,那白色就是9號了,因此我可以透過第二個顏色的序號找到正確的目標。」
諾斯克跟洛基說:「你的觀察力非常敏銳,你的網狀思考也已經打開了。的確雙色版的筷子遊戲的重點就在於第二個顏色是經過排序的,透過這樣的順序可以加速我們處理資料。」
大師將筒子收回,「遊戲到這裡結束,接下來讓我們回到 DynamoDB 吧。」
「主鍵在 DynamoDB 中有兩種型態,一種是單一主鍵,另一種叫複合主鍵。就像我們的筷子有單色版與雙色版一樣。」
「單一主鍵只有使用到 Partition key,為什麼叫 Partition key 我們稍後會再解釋。而複合主鍵則是 Partition Key 加上 Sort Key。」
大師接著詳細說明 Partition Key 是什麼。原來 DynamoDB 和關聯式資料庫有一個本質上的差異,就是 DynamoDB 是分散式的資料庫。分散式資料庫之所以出現的契機,在於人們需要處理超大資料量以及高速的寫入吞吐量,而這些都是以查詢見長的關聯式資料庫容易出現的瓶頸,只要資料量一多,查詢反應速度就會跟著受影響,而這個背後的癥結點,就是 Join 付出的昂貴效能代價。
DynamoDB 使用 Key-Value 的資料模型,最基礎的方式,就是單一主鍵──使用 Partition key。這個 key 會經過雜湊函數(hash function)計算,決定資料要存放在哪個分區(partition)。就像星際聯盟的郵政系統,每個星球都有獨特的編碼,所有寄往同一個星球的信件都會被送到該星球的轉運站。這個方法解決了儲存巨大資料量的問題,資料可以水平擴展到多個節點。
「要特別注意,」大師強調,「所有具有相同 Partition key 值的資料,一定會被存放在同一個物理分區中。就像剛才遊戲中,所有紅色(上層)的筷子都在同一批,所有綠色的在另一批。但是,看起來相似的 Partition key 值,例如 'USER#001' 和 'USER#002',會被雜湊函數分散到不同的分區,這樣才能避免熱點(hot partition)的問題。」
至於複合主鍵,就像我們的雙色筷子遊戲。上層顏色(Partition key)決定筷子在哪一批,下層顏色(Sort key)決定在這批中的順序。在 DynamoDB 中,所有具有相同 Partition key 的項目會在同一分區,並按照 Sort key 排序存放。
「舉個實際例子,」大師在白板上畫圖,「如果 Partition key 是 'B-613'(星球編號),Sort key 是 '2024-03-15#DEV-001'(日期和活動編號),那麼所有 B-613 星球的活動都會在同一個分區,並按日期順序排列。這就是為什麼 Sort key 又稱為 Range key——它讓你能在一個分區內進行範圍查詢,例如查詢三月份的所有活動。」
「也因為這樣的性質,所以昨天我們在建立資料表時,無論如何都需要事先定義一個 Key 來存放的原因在此。」諾斯克大師作了一個小結。
「接下來我要講的東西不難理解,但是卻是許多人在學習或是應用上的盲點,看待主鍵要當成它代表一組資料的位置,而不是資料本身。」大師嚴肅地說。
在 DynamoDB 的世界,資料處理都可以分解兩個步驟,首先依主鍵位置查詢那筆或那群資料,再來對資料進行各種操作。
就像有顏色的筷子一樣,我們不知道筷身寫什麼,我們只需要依照筷頭的顏色抽出來就好。在查詢的這個層級,是完全不關心資料本身是什麼樣的內容,它只關心能否找到主鍵。
也因此找到該筆資料後,你要對資料內容作什麼樣的異動都沒有關係,增加、刪減欄位,或是變更內容,主鍵完全不在乎這些事,也不會受到影響。
「也許用 SQL 來對比會更清晰」大師在螢幕中輸入了一個 SQL 指令。
SELECT * FROM IntergalacticEvents WHERE maxParticipants >= 100;
「在 SQL 的世界中,當 maxParticipants 這個資料的值一旦變動,查詢的結果就會不同。但是在 DynamoDB 的世界中,你某個欄位值無論如何變動,都不會影響到查詢的結果,因為資料是資料,主鍵是主鍵。除非你要為這個會變動的欄位特別設計一個查詢——那就是 GSI(全域次要索引)的用途,但那是後面的課程。」
「讓我舉個實際的例子,」大師在白板上畫圖,「假設我們用軍艦編號 'ROSE-BATTLESHIP-001' 作為主鍵:
主鍵層:ROSE-BATTLESHIP-001 → 指向資料位置
資料層:{
shipCode: "ROSE-BATTLESHIP-001", // 注意:這裡要重複存一次
shipName: "玫瑰號",
captain: "洛基",
status: "Active"
}
你可能會想:主鍵已經有軍艦編號了,為什麼資料中還要存一次?」
洛基點頭:「對啊,這不是重複了嗎?」
「這就是關鍵!」大師強調,「主鍵是用來『找到』資料的地址,而資料欄位是你『找到後要使用』的內容。如果你不在資料層存放 shipCode,當你取得資料後,你就無法在應用程式中使用這個編號。更重要的是,如果未來你需要更新顯示格式——例如把 'ROSE-BATTLESHIP-001' 改成簡碼 'RB-001'——你可以更新資料欄位,但主鍵永遠不變。」
「所以主鍵一旦建立就不能修改?」洛基問道。
「完全正確!在 DynamoDB 中,要『修改』主鍵的唯一方法是刪除舊項目、建立新項目。這也是為什麼主鍵設計如此重要——它是永恆的身份證。」
洛基筆記抄錄的滿滿的,抬頭問大師:「所以我可以在心裡想成主鍵和資料互相看不到對方,將他們分別開來,key 是 key,data 是 data?」
「這樣想很好,可以幫助你不會走錯路。」大師滿意地點頭。
「主鍵是靈魂的想法 Hippo 也許會跟你說至關重要,但我會說,那就是一切開始的地方。」