數據模型是開發軟體的最重要的部分,因為它們對應用程式有著深遠的影響:不僅是軟體的編寫方式,而且也影響我們如何解決的問題的方式。第二篇讀書筆記,我們聊一聊數據模型的設計。 1.數據模型的分層 作為一個開發者來說,在一個複雜的應用程式中,是存在很多 分層模型 的,但基本思想還是一樣的:每一層都提供了一個 ...
數據模型是開發軟體的最重要的部分,因為它們對應用程式有著深遠的影響:不僅是軟體的編寫方式,而且也影響我們如何解決的問題的方式。第二篇讀書筆記,我們聊一聊數據模型的設計。
1.數據模型的分層
作為一個開發者來說,在一個複雜的應用程式中,是存在很多分層模型的,但基本思想還是一樣的:每一層都提供了一個乾凈的數據模型,從而隱藏了底層的複雜性。通過這樣的抽象來允許不同的人群有效地協同工作。
每個數據模型都包含瞭如何使用它的假設。有些用法很容易,有些不支持;有些操作很快,有些執行不好;有些數據轉換很自然,有些則很笨拙。由於數據模型對其上層的應用程式能做什麼和不能做什麼有著深刻的影響,因此選擇適合於應用程式的數據模型十分重要。
(在這一章中,我們將完整的梳理各類數據模型和基於不同數據模型衍生的查詢語言)
2.數據模型
關係型數據模型
目前對電腦科學具有最深遠影響的數據模型就是SQL,基於Edgar Codd 提出了關係模型的對數據進行組織成表(SQL之中的表),其中每個元組稱之為行,行是一個無序的集合(SQL之中的行)。關係型的數據模型的目標將實現細節隱藏在一個更乾凈的介面後面。- 非關係型數據模型(NoSQL)
與關係數據模型相比,非關係型數據模型具有下麵的一些優點。包括了: - 非常大的數據容量與非常高的讀寫吞吐量。
- 很好地支持的專門查詢操作
數據模型會更加靈活
舉個慄子:
目前大多數應用程式開發都是使用面向對象編程語言完成的,這導致了對SQL數據模型靈活性的批評:數據存儲在關係表中,應用程式代碼中需要在對象與表、行和列的資料庫模型之間需要一個笨拙的轉換層。(也就是我們日常使用的ORM)
LinkedIn是我們常用的職業檔案網站,我們來看看使用不同數據模型的差異。
- 在傳統的SQL模型中,最常見的規範化表示是將位置、教育和聯繫人信息放在單獨的表中,帶有外鍵表引用到用戶表,如上圖所示。問題是顯而易見的,多表之間的依賴關係大大的複雜化了應用程式的編寫。
- JSON模型減少了應用程式代碼和存儲層之間匹配問題,它會更加靈活。如上圖所示,JSON表示相比多表模式具有更好的局部性。如果要獲得如教育或職業信息,在 多表模型之中您需要執行多次查詢(通過user_id查詢每個表)或執行一個多表連接的操作。而在JSON的數據模型之中,所有相關信息都在一個位置,一次查詢就足夠完成了。
(註:在例子中的前一段,region_id和industry_id給出的ID,不是純文本字元串“Greater Seattle Area”和“Philanthropy”。有如下幾個考量:(1)避免歧義(2)可以統一更新(3)可以更好的本地化來適應不同的語言。使用id的優點是,因為它對人類沒有意義,所以它不需要更改:id可以保持不變,即使它標識的信息是變化的。任何對人類有意義的東西都可能需要在將來某個時候改變,如果信息被覆制,所有多餘的副本都需要更新。這會導致寫開銷,並且不一致性的風險。區域和行業的列表可能很小,而且變化緩慢,以至於應用程式可以簡單地將它們保存在記憶體中。**)
文檔型數據模型的靈活性:
當應用程式希望改變其數據格式的情況下,靈活性就顯得至關重要了。 例如,假設我們在資料庫中將每個用戶的全名存儲在一個欄位中,而現在想要分別存儲名稱和姓氏。
文檔資料庫中,只需要開始使用新欄位編寫新文檔,併在應用程式中有代碼處理舊文檔讀取時的情況。
if (user && user.name && !user.first_name) { user.first_name = user.name.split(" ")[0]; }
在關係型資料庫模式中,通常按照這樣的思路修改模型:
ALTER TABLE users ADD COLUMN first_name text; UPDATE users SET first_name = split_part(name, ' ', 1); UPDATE users SET first_name = substring_index(name, ' ', 1);
在一個大數據量的表上運行UPDATE語句可能在任何資料庫上都很慢,因為每一行都需要重寫。如果這是不可接受的,應用程式可以讓first_name設置為其預設為填寫在讀的時候,通過這樣的方式來模擬文檔資料庫的靈活性。
小結:文檔型的數據模型的主要優點是模式靈活性,在局部性更好的性能,如程式經常需要訪問整個文檔時具有更好的性能優勢。對於特定的應用程式,它更接近應用程式所使用的數據結構。如果在應用程式中的數據具有類似文檔的結構(即一對多關係樹,通常是一次載入整個樹),那麼使用文檔模型會是一個好的選擇。關係型數據模型通過提供更好的連接支持、多對一和多對多關係,如果應用程式使用多對多關係,關係型數據模型會更加適合。通過在資料庫中生成多個請求,可以在應用程式代碼中模擬連接,但這也會將複雜性移動到應用程式中。
(文檔型資料庫開始支持表之間的關係查詢,連接操作。關係型資料庫開始引入JSON與XML的支持。混合型的數據模型或許會是資料庫發展的方向)
3.數據查詢語言
不知道大家有木有試想過一個問題,為什麼我們會有SQL語言。本身使用SQL語句表達的邏輯同樣可以用程式設計語言去表達,為何還需要多此一舉的使用另一種方式去表達數據模型呢?
其實這個答案是非必須的,也就是說,我們可以直接使用程式設計語言來和數據交互。(如:MongoDB就是使用了Js作為原生的交互語言。)但絕大多數我們直接使用的程式設計語言是命令式語言,而像SQL這種代數關係聲明式的查詢語言會有一些更貼合數據模型的優點。
舉個慄子:
例如,如果你有一個動物物種的列表,需要返回列表上的Shark:
由上圖所示,命令式語言告訴電腦按一定順序執行某些操作。你可以需要一行一行地單步執行代碼,評估條件,更新變數,並決定是否再迴圈一次。而在像SQL或關係代數這樣的聲明式查詢語言中,您只需指定您想要的數據的模式,結果必須滿足什麼條件,以及您希望如何轉換數據(例如,排序、分組和聚合),而不是具體的實現流程。資料庫系統的查詢優化器來決定哪些索引以及哪些連接方法可以使用,以及執行查詢的各個部分的順序。
- 聲明式查詢語言通常比命令式語言的API更簡潔,更易於使用。但更重要的是,它還隱藏了資料庫引擎的實現細節,這使得資料庫系統可以在不需要對查詢進行任何更改的情況下引入性能改進。
- 但SQL在功能上更為有限,靈活性上會受到限制,這給資料庫提供了更多的自動優化空間。
- 聲明式語言通常適合於並行執行,因為它們只指定結果的模式,而不是用於確定結果的演算法。
4.總結
數據模型是一個龐大的主題,所有不同的數據模型。現在都被廣泛使用,它們各自的領域都很好。一個模型可以用另一個模型來模擬,例如,文檔型的數據可以用關係資料庫表示,但結果往往很笨拙。這就是為什麼我們有不同的系統為了不同的目的,而不是一個單一的一刀切的解決方案。