何謂「反範式化」?

何謂「反範式化」?

寫在前面
爲了解決數據庫層的擴展問題,咱們已經討論了兩種方案:數據庫

Replication:從單庫擴展到多庫,以承載更多的請求量設計模式

Partitioning:把單庫(表)拆分紅多庫(表),打破單庫的性能瓶頸性能優化

在(多機)多庫多表的加持下,激增的請求量、數據量已經再也不是難題,然而,除卻數據量外,還有一個極其影響單庫性能的因素——數據的組織方式數據庫設計

例如,在關係型數據庫中,數據實體用二維表格(稱爲實體表)來描述:ide

何謂「反範式化」?

實體之間的複雜關聯關係(多對多)也經過二維表格(稱爲關係表)來描述:性能

何謂「反範式化」?

於是常常須要多表聯查才能獲得目標信息,關係越複雜,讀取性能越差,並最終像數據量同樣成爲單庫性能瓶頸,制約着數據庫層的可擴展性優化

那麼,對於關係型數據庫,有辦法進一步提高數據讀取性能嗎?ui

有,(在必定程度上)改變數據的組織方式,即反範式化(Denormalization)編碼

一.範式化
在討論反範式化以前,有必要先明確什麼是範式化,要反的東西是什麼?設計

Database normalization is the process of structuring a relational database in accordance with a series of so-called normal forms in order to reduce data redundancy and improve data integrity.

範式化(Database normalization),就是按照一系列範式(Normal forms)要求來組織數據模型的過程,目的是減小數據冗餘,提升數據完整性

試想,若是相同的信息在多行中重複出現,不相干的信息也湊在同一張表中,就很容易出現一些異常狀況:

更新異常:只更新單行,就會出現邏輯上的不一致

插入異常:沒法只插入部分信息,除非讓其它列先留空

刪除異常:刪除部分信息的同時,可能會波及其它無關信息

爲了不這些異常狀況,人們提出了一些約束規則,即數據庫設計範式

二.數據庫設計範式
1NF:第一範式(First normal form)要求數據表中每一個字段的值都不可再分

2NF:第二範式(Second normal form)在知足 1NF 的基礎上,要求全部非主屬性都徹底依賴於其主鍵

3NF:第三範式(Third normal form)在知足 2NF 的基礎上,要求全部非主屬性都不傳遞依賴於任何主鍵

P.S.此外,還有BCNF、4NF、5NF等等,具體見Normal forms

類比應用層,設計範式至關於數據層的設計模式,對數據表進行解耦,使單表信息更加內聚,彼此邊界分明,依賴關係更加清晰

咱們通常把知足 3NF 的關係模式(Relation schema)稱爲規範化的(Normalized),大多數狀況下都能規避上面提到的插入、更新和刪除異常。然而,在解決這些問題的同時,範式化也帶來了另外一些問題

三.範式化的弊端
在這些設計範式的約束下,相關聯的信息被存儲到了不一樣的邏輯表中:

A normalized design will often 「store」 different but related pieces of information in separate logical tables (called relations).

例如:

何謂「反範式化」?

3NF

以至於常常須要多表聯查(join操做),關係越複雜,連表查詢越慢:

If these relations are stored physically as separate disk files, completing a database query that draws information from several relations (a join operation) can be slow. If many relations are joined, it may be prohibitively slow.

那麼,有辦法能改善查詢性能嗎?

有。引入冗餘:

容許 DBMS 存儲額外的冗餘信息,例如索引視圖(indexed views)、物化視圖(materialized views),但仍聽從設計範式

增長冗餘數據,減小join操做,打破設計範式(即反範式化)

四.反範式化
所謂反範式化,是一種針對聽從設計範式的數據庫(關係模式)的性能優化策略:

Denormalization is a strategy used on a previously-normalized database to increase performance.

P.S.注意,反範式化不等於非範式化(Unnormalized form),反範式化必定發生在知足範式設計的基礎之上。前者至關於先遵照全部規則,再進行局部調整,故意打破一些規則,然後者全然不顧規則

經過增長冗餘數據或對數據進行分組,犧牲一部分寫入性能,換取更高的讀取性能:

In computing, denormalization is the process of trying to improve the read performance of a database, at the expense of losing some write performance, by adding redundant copies of data or by grouping data.

在設計範式的約束下,數據表中沒有冗餘信息(某個數據只存放在某張表的某個單元格中),爲了獲得某個數據可能須要一系列的跨表查詢,於是讀操做性能不佳,但寫操做很快,由於更新數據時只須要修改一處

反範式化就是要打破這種約束,把某些數據在不一樣的地方多放幾份,以加快數據檢索速度:

The opposite of normalization, denormalization is the process of putting one fact in many places.

具體操做
具體地,常見作法如:

存一些派生數據:相似於往 Redux Store 中塞計算屬性,把須要頻繁重複計算的結果存起來,例如在一對多關係中,把「多」的數量做爲「一」的屬性存儲起來

預先鏈接(pre-joined)生成彙總表:把須要頻繁join的表提早join好

採用硬編碼值:把依賴表中的常量值(或者不常常變化的值)直接硬編碼到當前表中,從而避免join操做

把詳情信息歸入主表中:對於數據量不大的詳情表,能夠把所有/部分詳情信息塞到主表中,以免join操做

P.S.關於反範式化具體作法的更多信息,見When and How You Should Denormalize a Relational Database

五.反範式化的代價
但除非必要,通常不建議反範式化,因其代價高昂:

失去了數據完整性保障:打破範式,意味着以前經過範式化解決的更新、插入、刪除異常問題又將從新冒出來,也就是說,冗餘數據的一致性要靠 DBA 本身來保證,而不像索引視圖等由 DBMS 來保證

犧牲了寫入速度:因爲反範式化引入了冗餘數據,更新時要修改多處,但大多數場景都是讀密集的,寫入慢一點問題不大

浪費了存儲空間:存儲了沒必要要的冗餘數據,天然會浪費一些存儲空間,但空間換時間通常是可接受的(畢竟內存、硬盤等資源已經相對廉價了)

P.S.通常經過約束規則(constraints)來保證冗餘數據的一致性,但這些規則又會抵消一部分做用

參考資料
Denormalization

Database normalization

DB2 Developer’s Guide-Fourth Edition

Database — Design: Logical Design (Part 6)

相關文章
相關標籤/搜索