一般我們在開發的時候,習慣上使用常規的關係型資料庫來設計資料庫表,對於一些業務表的欄位比較固定的場景,是一種非常不錯的選擇,而且查詢的時候,由於是基於固定的表欄位進行查詢,性能基本上是最優的。不過有一些場景下,業務信息的經常變化,使用常規的關係型資料庫來創建表欄位、刪除欄位的模式,肯定不是合適的處理... ...
一般我們在開發的時候,習慣上使用常規的關係型資料庫來設計資料庫表,對於一些業務表的欄位比較固定的場景,是一種非常不錯的選擇,而且查詢的時候,由於是基於固定的表欄位進行查詢,性能基本上是最優的。不過有一些場景下,業務信息的經常變化,使用常規的關係型資料庫來創建表欄位、刪除欄位的模式,肯定不是合適的處理方案,因此可能會進入JSON數據存儲的方式,而現今很多關係型資料庫也都支持JSON的存儲和子查詢處理,不過JSON的檢索還是比較麻煩,而且對於複雜的子查詢,性能據說也好不到哪裡。而非關係型資料庫的NoSQL資料庫(MongoDB資料庫),它的產生就是為瞭解決大規模數據集合多重數據種類帶來的挑戰。結合關係型資料庫的熟練使用、性能優勢和MongoDB資料庫的彈性化文檔處理特點,我對EAV模型(實體-屬性-值)的設計和低代碼的處理方案提供一個實用的思路供參考。
1、資料庫 EAV 模型設計
如果我們要做一個電商的商品管理,我們先賣一些衣服,需要管理衣服的尺碼、顏色、款式等信息;有一天需要賣電腦了,電腦需要 主板、CPU、顯卡、記憶體、硬碟、散熱 等信息;過幾天又需要賣手機了,手機有 顏色、版本、存儲容量、套餐類型等等信息。資料庫的頻繁更改,可能會導致開發的複雜度增加,說不准要重新處理。
如果我們每次新增商品,需要支持不同的信息的話就不停的加欄位。這樣會導致很多問題:
1、實現成本高,每次可能需要重新修改底層代碼,界面佈局及相關處理等
2、性能越來越差,每次增加的欄位,隨著複雜性越來越大,欄位越來越多,導致性能急劇下降。
3、維護越來越難,沒有好的系統規劃,就如在沙堆上建設豪華城堡,隨著時間的推移,越來越難維護。
還有一種是採用JSON數據存儲方案,對於擴展的數據,可以統一存儲在某個JSON裡面,這樣設計的擴展欄位,可以有效屏蔽一些複雜度,並提高彈性化。如可以把 尺碼、顏色、款色、主板、CPU、顯卡、記憶體等等都放到 JSON 里。
不過這樣JSON數據存儲方案,對於更新和條件查詢來說,性能是比較差的,隨著數據量和複雜度的增加,這種響應效果肯定不如意的,對於大數據的處理,這種處理肯定是災難性的。
EAV(Entity-Attribute-Value)模型是一種靈活的資料庫設計方法,特別適合存儲具有可變屬性的實體。
- Entity:實體,代表一個業務對象,比如上面的例子里的商品。
- Attribute:對象的屬性,屬性並不是作為實體單獨的一列來進行存放,而是存儲在一組單獨的資料庫表中。
- Value:指特定屬性所關聯的值。
在電商商品管理系統中,商品的屬性可能會變化,因此EAV模型是一個合適的選擇。每個實體都有唯一的標識符,每個實體都可以有多個屬性與之關聯,每個屬性都有唯一的標識符,每個屬性都可以具有多個值。
以下是一個簡單的EAV模型設計示例:
實體表(Entity Table):
這裡的實體是指商品。可能這裡用實體類型表述更準確。
屬性表(Attribute Table):
這裡的屬性是指商品的特征,例如顏色、尺寸等。
值表(Value Table):
這裡存儲了實體和屬性的關聯,以及具體的屬性值。
這樣設計的好處在於,你可以靈活地添加新的屬性,而無需修改資料庫結構。然而,EAV模型也有一些缺點,例如查詢可能會更加複雜,因為需要在值表中進行屬性值的連接。
2、優化的EAV模型
對於上面屬性值的存儲,統一都採用字元串的方式來存儲,這樣對於類型的處理和空間節約肯定是不好的,因此我們需要進行優化,根據不同的類型存儲在不同的表上。
上面屬性值沒有類型限制,都是 VARCHAR 的,對資料庫不友好,會導致記憶體浪費,而且存取都需要進行數據格式轉換。對存儲為字元串的值創建的索引不允許針對數值型和日期型的搜索範圍優化,這是採用混合數據類型的鍵-值對描述數據的公共問題。
我們對屬性值表基於數據類型進行分割,每個不同的數據類型拆為一個單獨的表,同時通過 屬性表(Attribute) 添加 類型決定去哪裡存取數據。
我們可以借鑒magento的eav模型,它是EAV設計的最優參考了。Magento 2中的EAV屬性類型有下麵這些表:
- eav_entity_int
- eav_entity_varchar
- eav_entity_text
- eav_entity_decimal
- eav_entity_datetime
這5種屬性類型就相當於欄位類型,一般關係型資料庫類型是通用的。
- int 對應欄位的int類型
- varchar 對應欄位的varchar類型
- text 對應欄位的text類型
- decimal 對應欄位的decimal類型
- datetime對應欄位的datetime類型
這樣分別不同類型的數據進行不同表的存儲了。
其他的屬性類似的處理即可。
參考下eav的設計圖,瞭解一下各個表之間的關係。
以及magento的eav模型設計圖,複雜的令人抓狂。
3、NoSQL資料庫的登場
使用EAV(Entity-Attribute-Value)模式來存儲完整的數據結構信息以及NoSQL資料庫來存儲完整的記錄是一種靈活的方法,特別適用於需要存儲動態結構數據的場景。
EAV的常規關係型資料庫表存儲常規的設計表,如實體類型、屬性定義、屬性值(多個)表的相關信息,而利用MongoDB資料庫的大數據處理靈活性和高性能的響應,能夠存儲我們實際變化的文檔信息。在檢索的時候,並提供了常規關係型資料庫的聯合查詢、JSON查詢無法得到的靈活性和高性能。好馬配好鞍,雙劍合璧,簡直完美。
在介紹實現我們的EAV模型設計的過程前,我們先來看看實際的界面效果
1)實體類型表和屬性定義處理
我們新增實體類型的時候,只需要填寫簡單的信息和類名即可,如果對於產品的定義。
屬性定義,除了指定屬性的一些名稱、排序、預設值、屬性值存儲類型外,還可以設置是否為字典列表、或者從其他類型表中選擇等處理。
有了欄位的定義,我們就可以在業務列表中顯示相關的欄位,並從MongoDB總檢索指定類型的數據,由於MongoDB本身支持非常好的查詢處理,因此對於查詢來說非常簡單。
如對於產品定義和數據展示來說,我們動態創建的菜單,根據實體類型的ID就可以進行通用的查詢了。如下界面所示。
這個表的數據在MongoDB中存儲的,如下界面所示。
對於有主從表的業務處理,也是同樣的處理方式,除了顯示主表的信息外,還需要展示明細的記錄數據,我們通過整合關係型資料庫的EAV表和MongoDB的文檔記錄顯示,就可以很好的展示相關的數據了。
我們在訂單明細表中選擇表的設置,我們可以再明細表格中動態進行數據的選擇處理, 並可以設置關聯複製的屬性欄位,如下界面所示。
訂單明細表的產品名稱屬性信息定義如下所示。
因為訂單明細表中,有時候需要複製來自產品信息的一些欄位,我們在按鈕【設置其他複製欄位】中處理映射關係即可。
這樣就可以自動引入選擇表的屬性值來填充了。
以上就是針對EAV模型設計,以及引入MongoDB來存儲詳細數據記錄,以便高效的查詢數據和處理動態化欄位內容的需求。
有時間會繼續寫文章介紹詳細的實現過程,以及界面的動態化處理模式。
專註於代碼生成工具、.Net/.NetCore 框架架構及軟體開發,以及各種Vue.js的前端技術應用。著有Winform開發框架/混合式開發框架、微信開發框架、Bootstrap開發框架、ABP開發框架、SqlSugar開發框架等框架產品。轉載請註明出處:撰寫人:伍華聰 http://www.iqidi.com