最近參加了一個PostgreSQL相關的茶會,感慨良多。原本話題是PostgreSQL 在 SELECT 場景中憑借其成熟的查詢優化器、豐富的功能特性和靈活的執行策略,展現出顯著優勢。在窗口函數(Window Functions)、JOIN 優化、公共表表達式(WITH/CTE) 等核心功能中,支持嚴格的關系代數和范式約束下的復雜查詢。結果后來,就跑題了,原因是有人提出這些特性其實用的極少。
筆者饒有興趣地聽完了全程,很感慨。本文就圍繞 “范式之殤 - 關系代數與參照完整性在 Web 后臺的落寞” 這一主題,簡要探討當下 WebApp 后端數據庫設計中存在的現象與問題。
如今,我們看到大量 WebApp 的后端數據庫背離了傳統關系型數據庫設計的核心原則,出現簡單表結構、字段冗余、參照完整性缺失等情況,數據庫系統強大的外鍵、檢查等特性被忽視,大量的一致性檢查交給Python后臺而不是DBMS本身。這是一種慵懶,還是因為新的數據和應用環境催生的工程妥協?
一、現象剖析:背離傳統設計原則的 Web 后臺數據庫
在傳統的關系型數據庫理論中,關系代數是數據處理的基石,它定義了選擇、投影、連接等一系列操作,確保數據在不同表之間以規范化的方式關聯與處理。參照完整性則通過外鍵約束等機制,保障數據的一致性和準確性,避免孤立數據與無效關聯。然而在當下的 WebApp 后端數據庫里,這些理論與機制卻逐漸失去了用武之地。
以常見的電商應用為例,按照規范設計,商品表、訂單表、用戶表之間應通過外鍵建立明確關聯,保證訂單引用的商品和用戶信息真實有效。但實際情況卻是,許多開發者為減少表連接操作,在訂單表中冗余商品名稱、用戶姓名等信息,導致數據更新時極易出現不一致問題。同時,由于缺失外鍵約束,訂單表可能存在引用不存在的商品 ID 或用戶 ID 的情況,造成數據混亂。在社交媒體應用中,用戶發布的動態、評論等數據,也常常忽視參照完整性,讓數據維護變得異常困難。
二、范式案例:教科書三范式在實際應用中的困境
在關系型數據庫設計中,范式是衡量數據庫結構合理性的重要標準,其中三范式(3NF)要求數據庫表中非主屬性不存在對碼的傳遞依賴。以一個在線教育系統為例,最初設計有一張 “課程信息表”,包含字段:課程 ID(主鍵)、課程名稱、教師 ID、教師姓名、教師聯系方式。在這個表中,教師姓名和教師聯系方式并不直接依賴于課程 ID,而是通過教師 ID 間接依賴,這就違反了三范式。以下是違反三范式的 “課程信息表” 結構:
字段名 | 類型 | 備注 |
---|---|---|
課程 ID | 主鍵 | 唯一標識課程 |
課程名稱 | 課程的名稱 | |
教師 ID | 標識授課教師 | |
教師姓名 | 教師的姓名 | |
教師聯系方式 | 教師的聯系方式 |
為了滿足三范式,我們需要將教師相關信息拆分出來,新建 “教師表”,包含教師 ID(主鍵)、教師姓名、教師聯系方式;“課程信息表” 則保留課程 ID(主鍵)、課程名稱、教師 ID,通過教師 ID 與 “教師表” 建立關聯。
滿足三范式后的 “課程信息表” 結構:
字段名 | 類型 | 備注 |
---|---|---|
課程 ID | 主鍵 | 唯一標識課程 |
課程名稱 | 課程的名稱 | |
教師 ID | 標識授課教師,關聯 “教師表” 的教師 ID |
滿足三范式后的 “教師表” 結構:
字段名 | 類型 | 備注 |
---|---|---|
教師 ID | 主鍵 | 唯一標識教師 |
教師姓名 | 教師的姓名 | |
教師聯系方式 | 教師的聯系方式 |
這種遵循三范式的設計在傳統單機數據庫中能有效減少數據冗余,保證數據的一致性。但在分布式數據庫和大數據場景下,卻暴露出諸多問題。
在分布式數據庫中,數據分散存儲在多個節點上,上述三范式設計會導致大量的跨節點表連接操作。例如,當查詢某課程及其授課教師信息時,需要在 “課程信息表” 所在節點和 “教師表” 所在節點之間進行數據傳輸與連接,這不僅增加了網絡開銷,還降低了查詢效率,嚴重影響系統性能。而在大數據場景中,數據處理強調的是快速讀取和分析海量數據,三范式嚴格的規范化設計使得數據分散在多個表中,在進行復雜的數據分析任務,如統計不同教師的課程數量及學生反饋情況時,需要進行大量的多表連接操作,這無疑增加了數據處理的復雜性和時間成本,難以滿足大數據實時性和高效性的要求。
三、現象緣由:開發效率與業務需求的權衡
(一)追求快速開發與迭代
在互聯網行業 “唯快不破” 的競爭環境下,快速開發和迭代成為 WebApp 開發的首要目標。傳統的關系型數據庫設計,尤其是遵循嚴格范式和參照完整性原則的設計,需要花費大量時間進行數據庫建模、表結構設計以及關系約束的定義。相比之下,采用簡單的表結構和字段冗余策略,開發者可以更快速地搭建起數據庫基礎架構,滿足業務初期的快速上線需求。例如,一些初創公司在開發初期,為了能在短時間內將產品推向市場,會選擇犧牲數據庫設計的規范性,優先實現功能。
(二)應對復雜多變的業務需求
WebApp 的業務需求往往具有高度的不確定性和快速變化的特點。新功能的不斷添加、業務流程的頻繁調整,使得嚴格遵循范式的數據庫設計難以適應。當需要對業務邏輯進行修改時,調整具有復雜關系約束和范式規范的數據庫結構成本極高,不僅需要修改表結構,還可能涉及到外鍵、觸發器等一系列的調整。而簡單的表結構和冗余字段,在應對業務變化時更加靈活,開發者可以直接在表中添加或修改字段,通過后端代碼來實現業務邏輯的調整,無需過多考慮數據庫結構的完整性和一致性。
(三)開發團隊技術認知與習慣
部分開發團隊對關系型數據庫的高級特性缺乏深入理解和熟練運用,更傾向于使用自己熟悉的后端代碼來處理數據關系和約束。Python 作為一種廣泛應用于 Web 開發的編程語言,具有簡潔易用、生態豐富的特點,很多開發者習慣通過 Python 代碼實現數據的增刪改查以及關系維護。例如,使用 Django、Flask 等框架的 ORM(對象關系映射)功能,雖然方便快捷,但在一定程度上掩蓋了數據庫底層的關系代數和參照完整性機制,導致開發者對數據庫原生特性的依賴降低。
四、深層次原因:技術生態與行業發展的影響
(一)非關系型數據庫的沖擊
近年來,非關系型數據庫(NoSQL)的興起對傳統關系型數據庫造成了巨大沖擊。NoSQL 數據庫以其靈活的數據模型、高可擴展性和高性能等特點,在處理海量數據、高并發訪問等場景下展現出獨特優勢。像 MongoDB 這樣的文檔型數據庫,采用類似 JSON 的文檔結構存儲數據,無需事先定義嚴格的表結構,非常適合快速變化的業務需求。Redis 作為鍵值對數據庫,在緩存、實時計算等場景中得到廣泛應用。這些非關系型數據庫的出現,讓開發者在數據庫選型時有了更多選擇,也促使他們在 WebApp 開發中嘗試打破傳統關系型數據庫的設計范式,選擇更靈活的方案。
(二)分布式架構與微服務的普及
隨著分布式架構和微服務的普及,WebApp 的后端架構變得越來越復雜。在微服務架構中,每個服務都有自己獨立的數據庫,服務之間通過 API 進行通信。這種架構模式下,數據的一致性和完整性維護面臨更大挑戰。為了降低服務之間的耦合度,減少跨服務的數據交互,各個微服務的數據庫往往采用相對獨立和簡單的設計,難以實現全局的關系代數和參照完整性約束。例如,一個電商系統拆分為用戶服務、商品服務、訂單服務等多個微服務,每個服務的數據庫各自獨立設計,用戶表、商品表、訂單表之間的關系難以通過傳統的數據庫約束來維護,更多地依賴于服務間的接口調用和業務邏輯處理。
(三)行業人才培養與技術導向
當前計算機教育和技術培訓體系中,對關系型數據庫高級特性的教學和實踐相對不足。很多開發者在學習過程中,更注重后端框架和編程語言的使用,對數據庫設計和優化缺乏深入學習。同時,行業內對技術的評價和導向也更傾向于功能實現的速度和創新性,忽視了數據庫設計的規范性和性能優化。這種人才培養和技術導向的偏差,導致開發團隊在實際項目中難以充分發揮關系型數據庫的強大功能,進而選擇更簡單但不規范的數據庫設計方案。
五、總結與展望
范式之殤,反映出關系代數與參照完整性在 Web 后臺逐漸落寞的現狀,這是多種因素共同作用的結果。雖然當前這種現象在 WebApp 開發中較為普遍,但我們不能因此否定關系型數據庫及其核心設計理念的價值。在一些對數據一致性、準確性要求較高的場景,如金融、醫療等領域,嚴格遵循范式和參照完整性原則的數據庫設計依然不可或缺。
未來,隨著技術的不斷發展,我們或許可以探索出更有效的解決方案,平衡快速開發與規范設計之間的矛盾。例如,結合人工智能和自動化工具,實現數據庫設計的智能優化和自動維護;進一步完善微服務架構下的數據一致性保障機制等。