DatabaseMongoDBData Modeling

MongoDB Schema 設計系列 (六):Subset Pattern 子集模式以優化記憶體使用

作者:Simon Cho
MongoDB Schema 設計系列 (六):Subset Pattern 子集模式以優化記憶體使用

MongoDB 資料建模的核心原則是「將常一起出現的資料放在一起」。但如果資料量過大、單個 document 包含太多欄位,導致工作集 (Working Set) 大到無法完整放進記憶體時,資料庫就會需要頻繁地從硬碟將資料載入 RAM (產生 Page Fault)。這會導致 query 的效能急劇下降,Subset Pattern (子集模式) 就是為了解決這個硬體資源限制下的效能問題。


Subset Pattern 的概念

Subset Pattern 的思考點非常直觀:

那些「常一起出現的資料」,真的每一次查詢都完全需要一起出現嗎?

有沒有可能其中一部分的欄位(例如:商品的所有歷史評論、電影幕後所有特技美術人員名單),只有在 5% 的特定情況下才會用到,而其他 95% 的主要流量只需要基本屬性?

如果是的話,我們就可以將這部分低頻率使用的欄位拆分出去,另行存放在另一個 collection 中。


具體做法與範例

Subset Pattern 主要是「用時間換取空間 (記憶體空間)」的策略。做法是將一個 collection 內的欄位區分為:

  1. 常用欄位:保留在原 Collection (Main Collection)。
  2. 低頻欄位:拆分到一個新的「詳細資訊」Collection。

[!TIP] 這樣做的好處是:我們可以確保在有限的實體記憶體空間內,RAM 快取的大部分都是高度活躍的「常用資料」,進而顯著減少硬碟與記憶體之間進行資料交換 (Paging) 的頻率,以此提升熱點查詢的吞吐量。

以電影資料庫 (IMDB) 為例

假設原本我們存的電影資料格式很龐大,包含了所有的幕後工作人員名單:

{ // movie
  "title": "Avengers: Endgame",
  "release_date": "2019-04-26",
  "genre": "Action/Sci-Fi",
  "director": "Russo Brothers",
  "actors": ["Robert Downey Jr.", "Chris Evans"],
  "box_office": "$2.798 Billion",
  "distributor": "Walt Disney",
  "shooting_location": "Atlanta, Georgia",
  "stunt_crew": ["Stunt Person A", "Stunt Person B", "......"],
  "vfx_crew": ["VFX Artist A", "VFX Artist B", "......"],
  "costume_crew": ["Costume Designer A", "......"],
  "art_crew": ["Art Director A", "......"]
}

在首頁或一般列表搜尋頁面,使用者通常只想看片名、發片日期、導演與主演。幕後特技人員、服裝道具、特效人員名單只有極少數影迷會點開「完整資料頁面」檢視。但每次查詢電影,整筆巨大的 Document 都會被載入記憶體,佔用寶貴的快取空間。

套用 Subset Pattern 後,我們可以將其拆分為兩個 collection:

{ // movie (常用子集)
  "_id": ObjectId("m1"),
  "title": "Avengers: Endgame",
  "release_date": "2019-04-26",
  "genre": "Action/Sci-Fi",
  "director": "Russo Brothers",
  "actors": ["Robert Downey Jr.", "Chris Evans"]
}

{ // movie_detailed (完整詳細資訊)
  "_id": ObjectId("md1"),
  "movie_id": ObjectId("m1"), // 關聯至主 Movie Collection
  "box_office": "$2.798 Billion",
  "distributor": "Walt Disney",
  "shooting_location": "Atlanta, Georgia",
  "stunt_crew": ["Stunt Person A", "Stunt Person B"],
  "vfx_crew": ["VFX Artist A", "VFX Artist B"],
  "costume_crew": ["Costume Designer A"],
  "art_crew": ["Art Director A"]
}

Subset Pattern Schema Design: 電影資料拆分常用子集

我們將不常用的幕後團隊名單欄位移到 movie_detailed 中,並透過 movie_id (或電影名稱與發片日期) 進行關聯。只有當使用者點擊「完整資訊」頁面時,系統才去查詢 movie_detailed

這能有效瘦身主資料庫的 Document Size,確保 Working Set 的記憶體被發揮到最高效益!

← 返回所有故事