SQL反模式學習筆記6 支持可變屬性【實體-屬性-值】
- 2019 年 10 月 4 日
- 筆記
目標:支持可變屬性
反模式:使用泛型屬性表。這種設計成為實體-屬性-值(EAV),也可叫做開放架構、名-值對。
優點:通過增加一張額外的表,可以有以下好處
(1)表中的列很少;
(2)新增屬性時,不需要新增列。不會影響現有表的結構;
(3)存儲的字段內容不會為空值。
缺點:(1)查詢語句變得更加複雜;
(2)使用EAV設計後,需要放棄傳統的數據庫設計所帶來的方便之處,比如:無法保障數據完整性;
(3)無法使用SQL的數據類型,比如對日期、金錢等格式內容都只能保持為字符串類型;
(4)無法確保引用完整性;
(5)無法配置屬性名。比如,有可能表中存在兩條記錄,
一條的attr_name是sex,一條attr_name是gender,都是表示性別;
(6)查詢結果中有多個屬性時,查詢非常困難,且查詢性能無法控制。
如何識別反模式:當出現以下情況時,可能是反模式
(1)數據庫不需要修改元數據庫(表中的列屬性)就可以擴展。還可以在運行時定義新的屬性。
(2)查詢是連接數量非常多,且連接的數量可能會達到數據庫的限制時,你的數據庫的設計可能是有問題的。
(3)普通的報表查詢變的及其複雜甚至不且實際。
合理使用反模式:
(1)關係數據庫中使用EAV,就意味着放棄許多關係數據庫範式的優點。
但是這不影響在某些程序中合理地使用這種設計來支持動態屬性。
(2)如果有非關係數據管理的需求,那最好的方法就是使用nosql數據庫。
在傳統數據庫中使用EAV設計的缺點也體現在這些非關係數據庫上。當元數據不具有固定格式時,
再簡單的查詢都會變得非常困難。上層應用就需要花費更多的時間、精力來組織數據結構。
解決方案:模型化子類型
1、單表繼承:所有屬性都在一個單表上保存,增加屬性時就擴充這個表。
當數據的子類型很少,以及子類型特殊屬性很少,就可以使用單表繼承。
缺點:(1)當程序需要加入新對象時,必須修改數據庫來適應這些新對象。又由於這些新對象具有一些和老對象不用的屬性,
因而必須在原有表裡增加新的屬性列,可能會遇到一個實際的問題,就是每張表的列的數量是有限制的。
(2)沒有任何的元信息來記錄哪個屬性屬於哪個子類型。
2、實體表繼承:為每個子類型創建一張獨立的表,每個表包含哪些屬於基類的共有屬性,同時也包含了子類型特殊化的屬性。
優點:(1)實體繼承類設計相比於但表繼承設計的優勢在於提供了一種方法,
讓你能組織在一行內存儲一些和當前子類型無關的屬性。
如果你引用一個並不存在於這張表中的屬性列,數據庫會自動提示你錯誤。
(2)不用像在單表繼承設計里那樣使用額外的屬性來標記子類型。
缺點:很難將通用屬性和子類特有屬性區分開來。因此,如果將一個新的屬性增加到通用屬性中,
必須為每個子類表都添加一遍。
當你很少需要一次性查詢多有子類型時,實體繼承表設計是最好的選擇。
3、類表繼承:把表當成面向對象里的類。
創建一張基類表,包含所有子類型的公共屬性。對於每個子類型,創建一個獨立的表,通過外鍵和基類表相連。
4、半結構化數據模型:如果有很多子類型或者必須經常增加新的屬性支持,那麼可以用一個BLOB列來存儲數據,
用XML或者JSON格式——同事包含了屬性的名字和值。這叫做序列化大對象塊。
這個設計的優勢是擴展性,缺點是,這樣的結構中sql無法獲取某個指定的屬性。你必須或者整個blob字段並通過程序去解釋這些屬性。
當你需要絕對的靈活性時,可以使用這個方案。
如果使用了EAV,那麼可以先將全部屬性取出,然後再做其他處理。