---
title: 非規范化
slug: denormalization
date: 0010/01/02
number: 10.5
points: 10
sidebar: true
photoUrl: http://www.flickr.com/photos/ikewinski/9283093547/
photoAuthor: Mike Lewinski
contents: 理解非規范化是什么。|Mongo 與傳統的關系型數據庫的比較。|了解什么時候你*不要*非規范化數據。
paragraphs: 15
---
非規范化數據不存儲規范化的數據。換句話說非規范化意味著相同數據的多個拷貝同時存在。
上一章中,我們在帖子中非規范化評論總數,以避免每次都加載所有的評論。在數據建模意義上說這是冗余的,因為我們可以通過計數每個評論,隨時計算出該總數(當不考慮運行速度)。
非規范化通常意味著額外的開發工作。在例子中,我們每次添加或刪除評論時,還需要同時更新相關的帖子,以確保 `commentsCount` 字段保持準確。這就是為什么關系型數據庫,比如 MySQL,對這種做法不以為然。
但是,規范化做法也有其缺點:沒有 `commentsCount` 項,就象開始我們做的那樣,為了計算評論總數,每次我們都需要傳輸_所有_的評論。非規范化使我們能夠完全避免這種情況。
<% note do %>
### 一份特殊發布
我們可以創建一個特殊的發布,送出我們有興趣的的評論數(通過聚合查詢服務器,我們目前能看到帖子的評論數)。
如果這樣發布代碼的復雜性不超過由非規范化造成的難度,它是值得考慮的...
<% end %>
當然,這樣的考慮是和應用相關的:如果你寫的代碼,數據完整性是非常重要的,那么避免數據的不一致,就比性能提升,更為重要和更有較高優先級。
### 嵌入文件或使用多個集合
如果您是有 Mongo 的經驗,你可能會感到驚奇,我們給評論單獨創建了第二個集合:為什么不直接在帖子文檔中嵌入評論?
事實證明當進行集合操作時,Mongo 提供的許多工具會給我們帶來更好的結果。例如:
1. `{{#each}}` helper 遍歷游標(`collection.find()` 的結果)是非常有效的。但是當它遍歷一個較大文件中的對象數組時,效率就不高。
2. `allow` 和 `deny` 在 document 文檔級別上操作,因此可以很容易地確保每個評論修改的正確性,但是在帖子級別就會變得更復雜。
3. DDP 在文檔的頂級屬性級操作————這意味著,如果 `comment` 是 `post` 的一個屬性,每當在帖子上創建一個新評論時,服務器就會將該帖子的整個更新的評論列表發送到每個連接的客戶端。
4. 在文檔級別更容易控制發布和訂閱。例如,我們想對帖子的評論進行分頁,如果評論沒有屬于它們自己的集合,我們會發現很難做到。
Mongo 推薦嵌入文檔以減少昂貴的查詢次數。然而,考慮到 Meteor 的架構,就不成問題了:大多數時候我們在*客戶端*查詢評論,其數據庫訪問基本上是沒有的。
<% note do %>
### 非規范化的缺點
也有很好的理由使你*不要*非規范化數據。為了更好地理解反對非規范化的情況,我們推薦閱讀 Sarah Mei 寫的[為什么你不應該使用 MongoDB](http://www.sarahmei.com/blog/2013/11/11/why-you-should-never-use-mongodb/)。
<% end %>