MongoDB - 數據模型的設計模式

来源:https://www.cnblogs.com/fatedeity/archive/2022/12/13/16977740.html
-Advertisement-
Play Games

在實際開發中,大多數性能問題都可以追溯到糟糕的模型設計。官方也提供分享過文檔模型設計的進階技巧,這裡簡單翻譯記錄一下。 ...


簡介

官方文章的地址是 Building with Patterns: A Summary,其中彙總了 12 種設計模式及使用場景。

設計模式彙總表

上述的圖表列舉了 12 種設計模式及應用場景,主要是以下這些:

  • 近似值模式(Approximation Pattern)
  • 屬性模式(Attribute Pattern)
  • 桶模式(Bucket Pattern)
  • 計算模式(Computed Pattern)
  • 文檔版本控制模式(Document Versioning Pattern)
  • 擴展引用模式(Extended Peference Pattern)
  • 異常值模式(Outlier Pattern)
  • 預分配模式(Preallocated Pattern)
  • 多態模式(Polymorphic Pattern)
  • 模式版本控制模式(Schema Versioning Pattern)
  • 子集模式(Subset Pattern)
  • 樹型模式(Tree and Graph Pattern)

近似值模式

示例描述

淘寶在往年“雙十一”都會有一個銷售額大屏展示,當銷售額小於 1 億時,可能展示的是實際的數量,當銷售額超過 1 億時,單位立即變成以“億”為單位,對於展示的大屏而言,”億“以下的單位這個時候並不是很重要了。

對於上述的場景,如果每次幾十、幾百都直接去更新資料庫中的實際值,則更新資料庫會變得非常頻繁,對於資料庫的壓力是非常大的。

實際上,並不需要每次都去更新資料庫,我們只需要將這個實際的精確值存儲在記憶體中,使用 1 億作為一個閾值,一旦超過這個閾值就精確值更新進資料庫中。

對於精度不是首要考慮因素時,那麼就可以使用近似值模式,尤其是消耗資源(時間、記憶體、CPU 周期)非常昂貴時效果會更佳。

近似值模式就是通過減少數據的寫入頻率,從而降低了架構的複雜度和資源開銷,進而提升了整體的性能與效率。

優缺點

近似值模式的優點如下:

  • 由於是近似的數據,不必時時刻刻寫入,資料庫的寫操作量級更小

近似值模式的缺點如下:

  • 存儲的是近似的數據,無法應對需要展示精確數據的場景
  • 此模式需要在應用層實現

屬性模式

示例描述

屬性模式運用到了 MongoDB 多鍵索引的概念,支持對數組中的嵌套子文檔中的某個屬性進行索引。

假設現在有一個關於電影的集合,其中文檔中會包含標題、導演、製片人、演員、上映時間等等信息,對於跨地區上映的電影,有可能不同地區的上映時間是不一樣的。

如下展示是一條電影的文檔數據:

{
    "title": "Star Wars",
    "director": "George Lucas",
    // 不同地區有不同的上映時間
    "release_US": ISODate("1977-05-20T01:00:00+01:00"),
    "release_France": ISODate("1977-10-19T01:00:00+01:00"),
    "release_Italy": ISODate("1977-10-20T01:00:00+01:00"),
    "release_UK": ISODate("1977-12-27T01:00:00+01:00"),
}

為了支持對所有上映時間做一個快速搜索,也許我們需要將所有的上映時間設置為單一索引,這個時候,索引的數量就會變得顯而易見的多。

使用屬性模式,我們通過將這些上映時間信息移動到一個數組中,然後再對這個數組建立一個多鍵索引索引,以實現使用一個索引替代多個類似索引的功能。

如下是修改結構後的文檔數據:

{
    "title": "Star Wars",
    "director": "George Lucas",
    // 所有的地區的上映時間都放在同一個屬性內部
    "releaseList": [
        {
            "region": "US",
            "date": ISODate("1977-05-20T01:00:00+01:00")
        },
        {
            "region": "France",
            "date": ISODate("1977-10-19T01:00:00+01:00")
        },
        {
            "region": "Italy",
            "date": ISODate("1977-10-20T01:00:00+01:00")
        },
        {
            "region": "UK",
            "date": ISODate("1977-12-27T01:00:00+01:00")
        }
    ]
}

優缺點

屬性模式的優點如下:

  • 需要更少的索引
  • 查詢變得更容易編寫,而且通常更快

桶模式

示例描述

桶模式有點類似於水平分庫,常見的水平分庫是將一個集合按照某一個規則分佈到不同的資料庫上,桶模式是將一個集合中的文檔按照某一個規則合併起來。

假設現在有一個需要記錄用戶日誌的需求,對於用戶的每一個動作,都需要將其更新到 MongoDB 當中,並且是記錄其動作、時間。

對於這樣的日誌數據來說,如果將每一個動作都存儲成一個文檔,則將會占用極大的存儲空間和記憶體。

使用桶模式的解決辦法就是,將一段時間的日誌數據存儲成一個文檔,再將每一個動作日誌的數據存儲到子文檔數據中。

當需要管理流式數據的時候,如時間序列、實時分析或物聯網應用程式,桶模式就是一個很好的解決方案。

優缺點

桶模式的優點如下:

  • 減少了集合中的文檔總數
  • 提高了索引性能
  • 可以通過預聚合簡化數據的訪問

計算模式

示例描述

對於大型數據集,每一次計算都可能會占用極大的 CPU、磁碟、記憶體等相關資源,甚至是影響到伺服器上的其他計算。

而對於需要重覆計算、讀取比寫入多的場景,計算模式提供了一種優化的思路,以便降低伺服器資源的占用。

拿一個電影觀看總人數的例子來說明:假設現在頁面上需要展示觀看電影的實際總人數,而且這個頁面會有成千上萬的人訪問。

雖然,我們可以對電影的每一次放映都記錄起觀看人數,但是要獲取總人數,則需要拿出所有的放映場次的觀看人數之後計算其總和,這個計算就非常耗費資源和時間。

對於只有放映場次變化之後,總人數才會更新的情況,實際資料庫讀取的次數遠遠大於寫入的次數。

MongoDB 的計算模式

在這個場景中,計算模式的思路是:每一次更新放映場次數據的時候,將這個放映場次的人數彙總到一個文檔當中,這個文檔直接面向用戶的查詢。

優缺點

計算模式的優點如下:

  • 對於頻繁的計算可以減少 CPU 的負載
  • 查詢變得更容易編寫,而且通常更快

計算模式的缺點如下:

  • 識別出需要使用此模式的的場景可能比較困難
  • 除非必要,請勿過度使用此模式

文檔版本控制模式

示例描述

文檔版本控制模式在高度規範化的行業中非常有用,這些行業會要求數據的特定時間點版本。

假設現在有一個博客系統,其中有一個記錄每次編輯博客文章歷史的功能,這樣的功能就能應用文檔版本控制模式。

假設我們將所有的文章歷史都存儲在同一個集合當中,則需要考慮大部分與文章相關的功能都要過濾掉歷史版本、版本越多則集合文檔數量越多等等問題。

文檔版本控制模式的想法是:文檔中需要記錄一個文檔的版本,將最新的文檔保存在一個 current 集合中,而那些舊版本的文檔保存在 history 集合中。

為了最大化利用文檔版本控制模式的優勢,通常會假設數據訪問模式儘量符合以下要求:

  • 每個文檔不會有太多的修訂版本
  • 需要做版本控制的文檔不會太多
  • 大多數的查詢都是基於文檔的最新版本

優缺點

文檔版本控制模式的優點如下:

  • 容易實現,對現有系統的影響小
  • 在最新版本上進行請求時,沒有性能上的影響

文檔版本控制模式的缺點如下:

  • 寫操作的數量會翻倍
  • 請求需要被定位到正確的集合

擴展引用模式

示例描述

MongoDB 是一個不需要提前建模的 NoSQL,當不同文檔、不同集合之間存在關係的時候,通常會有嵌入和引用兩種方式。

嵌入就是將文檔數據嵌入到引用此數據的文檔中,訪問時直接訪問這一次文檔即可;引用就是只在文檔中引用另一個文檔的標識,訪問時需要訪問兩次資料庫才能拿到完整的數據。

擴展引用模式是指僅複製經常訪問並且不經常更改的欄位,而不是複製所有的數據,減少信息的連接以提高性能。

擴展引用模式引用數據

這張圖的場景是:客戶和訂單是 1 對 N 的關係,通常查詢訂單列表的時候需要展示客戶的一些信息,我們就需要考慮是否將客戶的信息冗餘進訂單信息中。

擴展引用模式認為,客戶的名稱和地址是不常做更新的,可以直接將這些信息冗餘進訂單表中,以達到減少兩個集合連接查詢的要求。

優缺點

擴展引用模式的優點如下:

  • 當有大量的 JOIN 操作時可以提升性能
  • 讀操作會更快,並且可以減少 JOIN 操作的數量

擴展引用模式的缺點如下:

  • 修改冗餘的這部分數據會比較複雜

異常值模式

示例描述

顧名思義,異常值模式主要用以解決超出應用程式正常模式的少數異常查詢情況。

假設你正在搭建一個出售圖書的電子商務網站,現在需要記錄一本書都有哪些用戶購買過,一個常見的做法的是將購買的用戶標識存儲在圖書文檔中,如下展示:

{
    "_id": ObjectId('6392cecd4dd9624424ad025d'),
    "title": "三國演義",
    "author": "羅貫中",
    "purchase_customers": [
        "user0",
        "user1",
        "user3",
        // ...
    ]
}

對於上述的文檔結構,大部分情況下是適用的。但是,對於銷量特別高的圖書,極可能導致圖書文檔的大小超過 16MB 的限制。

使用異常值模式的方式是:在圖書文檔中添加一個欄位來將其標記為異常值,超過一定大小的內容可以存儲在另一個文檔當中,在應用程式中對異常文檔做擴展查詢處理,減少異常文檔對正常文檔的影響。

優缺點

異常值模式的優點如下:

  • 防止整個應用被某些異常的文檔或請求所影響
  • 請求會針對那些典型的用例進行優化,而異常值仍將得到處理

異常值模式的缺點如下:

  • 通常會為特定的查詢而進行定製,因此一些臨時產生的查詢可能性能不太理想
  • 此模式的大部分工作是在應用程式代碼中完成的

預分配模式

示例描述

在使用 MMAPv1 存儲引擎時,MongoDB 的一個常見優化是提前分配所需的記憶體,以滿足不斷增長的文檔未來會達到的大小。

MMAPv1 中不斷增長的文檔需要由服務端以相當昂貴的成本進行位置的遷移,而 WiredTiger 的無鎖機制(lock-free)和重寫(rewrite)更新演算法不需要這種處理。

一個相對應的例子就是,直接存儲一個二維數據可以做到預分配記憶體,而存儲二維數組轉換後的稀疏數組則無法做到預分配記憶體。

因此,在 MMAPv1 中,更推薦使用預分配模式直接存儲原始的二維數組。

優缺點

預分配模式的優點如下:

  • 當預先知道文檔結構時,可以簡化設計

預分配模式的缺點如下:

  • 簡單和性能之間的權衡

多態模式

示例描述

在面向對象中,多態指的是為不同數據類型的實體提供統一的介面,或使用一個單一的符號來表示多個不同的類型。

而 MongoDB 不強制要求集合的文檔擁有特定的結構,這裡的多態模式指的是,集合中的文檔具有更多的相似性而不是差異性,文檔結構都類似但又不完全相同。

其一種實現方案是將文檔分組在一起做查詢,而不是將其分散到多個集合中;另一種實現方案是使用嵌入式子文檔的模式彙總。

多態模式的一個典型用例是單一視圖應用程式:假設現在一家較大的公司收購了其他公司,這些公司的業務都是類似的,資料庫都以類似的方式存儲了數據。

這個時候就可以利用 MongoDB 和多態模式在短時間內構建好單一視圖應用程式。

除了單一視圖應用程式外,多態模式的其他典型用例還有以下幾種:

  • 內容管理
  • 移動應用程式
  • 產品目錄

優缺點

多態模式的優點如下:

  • 實現簡單
  • 查詢可以在單個集合中運行

模式版本控制模式

示例描述

幾乎每個資料庫在其生命周期中的某個時刻都會產生變更,一旦資料庫中的數據模型發生變化,通常需要停止應用程式,遷移資料庫以支持新模式,然後重新啟動。

這種停機更新會導致糟糕的用戶體驗,而模式版本控制模式允許歷史版本和當前版本的文檔在集合中同時存在,以此保障用戶體驗。

通過使用 schema_version 欄位定義模式的版本,並將其保存到資料庫中,每個新的模式版本都會增加 schema_version 欄位的值。

在應用程式內部,為每個模式版本創建相應的處理函數,這樣即可適應不同版本的數據。

優缺點

模式版本控制模式的優點如下:

  • 不需要停機時間
  • 模式遷移可控
  • 減少未來的技術債務

模式版本控制模式的缺點如下:

  • 在遷移過程中,對相同的欄位可能需要兩個索引

子集模式

示例描述

MongoDB 將頻繁訪問的數據保存在 RAM 中,當數據和索引的工作集超過分配的物理 RAM 時,隨著磁碟訪問的發生以及數據從 RAM 中轉出,性能會開始下降。

為解決這個問題,一個方案是向伺服器添加更多的 RAM,不過擴展會有上限,而且非常昂貴;或者考慮對集合進行分片,但這會帶來額外的成本和複雜性。

子集模式就解決了有大量數據的大文檔沒有被應用程式使用而導致的工作集超過 RAM 容量的問題,比如說一個電商產品的評論可能有成千上萬條,但大部分情況下都只會訪問最近 10 個評論。

其實現方法就是,將一個存儲大文檔的集合拆分成多個子集,每一個子集都能為單獨的功能提供資源,減少了工作集的總體大小。

優缺點

子集模式的優點如下:

  • 在總體上減小了工作集的大小
  • 縮短了最常用數據的磁碟訪問時間

子集模式的缺點如下:

  • 必須管理子集
  • 請求附加的數據需要額外的資料庫訪問

樹形模式

示例描述

對於 SQL 來說,可以通過外鏈子結點或父結點的方式表示樹形結構。

對於 MongoDB 而言,比較方便的就是通過存儲子結點數組的方式實現,但是其缺點就是每次更新時都需要操作整個結構,不合適做頻繁更新,比如說家譜。

因此,當數據是分層結構並且經常被查詢時,樹形模式是比較優的一個選擇。並且可以通過給數組中的屬性創建多鍵索引提高查詢效率。

優缺點

樹形模式的優點如下:

  • 通過避免多次 JOIN 操作提高了性能

樹形模式的缺點如下:

  • 需要在應用程式中管理樹結構的更新

首發於「程式員翔仔」,點擊查看更多。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天和小伙伴日常在群內吹水的時候,有群友問了這樣一個問題: 腳本文件第一行加個 #!/usr/bin/bash 有什麼用呢? 其實,除了這種之外,還有很多其他寫法,比如: #!/bin/bash #!/usr/bin/env bash #!/bin/awk 這些寫法大同小異,但很多同學像我一樣,在之 ...
  • 通過編譯安裝的時候指定echo模塊,實現列印輸出變數的值。 # 客戶端地址:10.0.0.66 root@ubuntu1804:~# curl 10.0.0.44/x/y/z?name=bob?passwd=123 remote_addr: 10.0.0.66 #客戶端ip地址 args: name ...
  • "天底下沒有完美的資料庫,也許Oracle是個例外”,前陣子幾個DBA在討論國產化替代時,有人就這麼說。確實是的,Oracle算是比較完美的資料庫產品了,不過現在很多用戶都在面臨從Oracle資料庫向其他資料庫遷移的問題。中國電信已經宣佈了今年年底前全線下架Oracle資料庫,全部用國產或者開源數據... ...
  • Redis項目總結--緩存穿透、緩存雪崩、緩存擊穿 一.緩存穿透 1.什麼是緩存穿透 查詢某個 Key 對應的數據,Redis 緩存中沒有相應的數據,則直接到資料庫中查詢。資料庫中也不存在要查詢的數據,則資料庫會返回空,而 Redis 也不會緩存這個空結果。這就造成每次通過這樣的 Key 去查詢數據 ...
  • 1.關於Yearning Yearning是一個Sql審核平臺,底層使用Go語言,安裝和部署方式也很便捷 項目地址 https://guide.yearning.io/install.html github地址 https://github.com/cookieY/Yearning/releases ...
  • GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 GreatSQL是MySQL的國產分支版本,使用上與MySQL一致。 作者:xryz 文章來源:社區投稿 使用方法 1、首先創建一個測試表test1,並插入幾條數據: mysql> create table test1 ( ...
  • 索引必知必會 索引原理 沒有索引的時候,搜索是全表進行掃描,速度很慢; 當我們建立了一個索引後,會生成一個索引的數據結構(例如索引二叉樹) 代價 索引會占用磁碟空間 對增刪改語句的效率有影響 -> 結合實際場景是查詢業務多還是增刪改業務多來判斷 所以不能盲目添加 規則 頻繁作為查詢條件的欄位可以創建 ...
  • “智能標簽平臺上線後,支行及業務部門已創建多個客群用於營銷,為我行客戶精細化管理打下了良好基礎。” 杭州聯合銀行始終以服務市民、小微企業、經濟組織和地方經濟發展為己任,本著“做小、做散、做深”的原則,通過促進機制轉型、優化業務流程、豐富產品體系、強化風險管控、等一系列手段,逐步形成了具有自身特色的“ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...