接續昨天提到 Document Database 是 Schemaless,也就是的不須預先定義 Schema 且資料庫也不會替你控管的特性,這讓我們可以在資料做出具有多型 (Polymorphic) 特性的 Schema 設計。我們的程式碼有多類別型設計時,以往使用關聯式資料庫通常會靠拆表或設定成 Nullable 欄位來處理各個子類別特化的資料,在使用 Document Database 時就可以直接轉成 Document,因為不同的 Document 不需要有完全一致的 Schema。
以寵物資訊為例,所有的寵物都具有一些共同的資訊,例如;姓名、生日、飼主姓名、飼主聯絡電話和體重等。
class Pet
{
int Id;
string Name;
DateTime Birthday;
float Weight;
string OwnerName;
string ContectPhone;
Species Species;
}
但不同動物可能會有不同的資訊,例如外觀描述,貓的外觀描述包含毛皮、眼睛和鬍鬚、臉型、尾巴形狀和是否剪耳,但刺蝟則是刺的顏色和眼睛顏色。
class Cat : Pet
{
SkinType Skin;
Color EyeColor;
Shape FaceShape;
Shape TailShape;
bool IsEarCut;
}
class Hedgehog : Pet
{
Color PrickColor;
Color EyeColor;
}
如果是關聯式資料庫,我們的資料表設計可能會有一張主表 Pet 關聯 Cat 和 Hedgehog 兩張子表;或是只開一張 Pet 資料表,並將 Cat 和 Hedgehog 有的欄位通通放進去,但因為不是每隻寵物的每個欄位都會有這些資料,所以這些欄位都需要設定為 Nullable。使用 Document Database 時,就可以同時將 Cat 和 Hedgehog 放在同個 Collection。
{
"Id": 1,
"Name": "MyCat",
"Birthday": "2000-10-10",
"Weight": 4.6,
"OwnerName": "Owen",
"ContectPhone": "0912345678",
"Skin": "Black",
"EyeColor": "Yellow",
"FaceShape": "Triangle",
"TailShape": "Short",
"IsEarCut": false
}
{
"Id": 2,
"Name": "MyHedgehog",
"Birthday": "2000-10-10",
"Weight": 0.7,
"OwnerName": "Owen",
"ContectPhone": "0912345678",
"PrickColor": "Chocolate",
"EyeColor": "Black"
}
Document Database 一樣會將資料分片,每個 Collection 中的資料都會擁有一個或多個共同的欄位被設定成 Sharding Key,作為分片的依據。Sharding Key 的選擇方式大致方為三種:Range-based、Hash 和 List-based。具有時間性的資料和應用場景很適合使用時間作為 Range-based Sharding Key,像是用來產生BI報表的資料;Hash Function 通常可以讓資料平均分布,因此透過 Hash Sharding Key 可以預期每個分片的大小不會差太多;List-based 的切片方式則是以資料類型作為依據,有點類似大賣場的商品品項繁多,所以會有生鮮區、五金區、零食區、清潔用品區等等分區這樣的概念,能確保通常一起被存取的資料會被放在同個分片中。
在關聯式資料庫,開發者會透過正規化和反正規化的方式設計出符合需求的 Schema,這樣的行為其實跟在設計 Document 時很類似。對資料庫的操作可以簡單的分成增刪修和查詢兩類,正規化的目的是為了降低增刪修時的負擔,透過避免重複資料達到每次的增刪修可以異動最少的地方;反正規化則是為了減輕查詢時的負擔,盡可能的減少需要對資料表進行Join和掃描的行為,就能提升效率。在設計 Document Database 時,通常會為了它的彈性和可擴展性減少正規化的設計(相較於設計關聯式資料庫時),盡可能減少跨 Document 查詢的可能性,這也表示相同資料很可能重複出現在不同的 Document 中,而應用程式端必須顧好多副本的一致性。