跳到主要內容
黯羽輕揚每天積累一點點

Database Denormalization_系統設計筆記 11

免費2020-03-15#Back-End#why denormalization#反范式化#范式化#反范式化具体操作#反范式化案例

對於關係型資料庫,有辦法進一步提升資料讀取性能嗎?

寫在前面

為了解決資料庫層的擴充套件問題,我們已經討論了兩種方案:

  • Replication:從單庫擴充套件到多庫,以承載更多的請求量

  • Partitioning:把單庫(表)拆分成多庫(表),打破單庫的性能瓶頸

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

例如,在關係型資料庫中,資料實體用二維表格(稱為實體表)來描述:

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

因而經常需要多表聯查才能得到目標資訊,關係越複雜,讀取性能越差,並最終像資料量一樣成為單庫���能瓶頸,制約著資料庫層的可擴充套件性

那麼,對於關係型資料庫,有辦法進一步提升資料讀取性能嗎?

有,(在一定程度上)改變資料的組織方式,即反範式化(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)要求來組織資料模型的過程,目的是減少資料冗餘,提高 資料完整性

試想,如果相同的資訊在多行中重複出現,不相干的資訊也湊在同一張表中,就很容易出現一些異常情況:

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

  • 插入異常:無法只插入部分資訊,除非讓其它列先留空

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

為了避免這些異常情況,人們提出了一些約束規則,即資料庫設計範式

二。資料庫設計範式

P.S. 此外,還有 BCNF4NF5NF 等等,具體見 Normal forms

類比應用層,設計範式相當於資料層的設計模式,對資料表進行解耦,使單表資訊更加內聚,彼此邊界分明,依賴關係更加清晰

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

三。範式化的弊端

在這些設計範式的約束下,相關聯的資訊被儲存到了不同的邏輯表中

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

例如:

[caption id="attachment_2131" align="alignnone" width="625"]3NF 3NF[/caption]

以至於經常需要多表聯查(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)來保證冗餘資料的一致性,但這些規則又會抵消一部分作用

參考資料

評論

暫無評論,快來發表你的看法吧

提交評論