2012-04-11 83 views
2

我有一個基本的CRUD網絡應用程序,人們可以創建文章/編輯它們。我現在想添加修改所有修改歷史記錄的功能。目前,我有一個文章表,看起來像這樣:規範化或反規範化將修訂歷史存儲在RDBMS中?

Article(id, title, content, author_id, category_id, format) 

我已經考慮了2個選項來改變我當前的模式,以添加對修訂歷史的支持。基本思想是任何文章的每一個編輯都會作爲記錄存儲在修訂表中。所以文章和修訂是一對多的關係。

第一個選項(標準化): 一個用於文章元數據的表格,一個用於修訂版本。沒有重複的數據存儲。

Article(id, title, category_id) 
Revision(id, content, author_id, format) 

第二個選項(非歸): 兩個表像選項1,但一些重複列。

Article(id, title, content, author_id, category_id, format) 
Revision(id, article_id, content, author_id, format) 

我正在考慮去第二個選項,因爲它會使我的編碼更容易(不太複雜,代碼行少)。我知道這不是「學術」和「純粹」,但我個人的感覺是,必須進行額外的連接會傷害代碼維護。此外,性能應該更好,因爲沒有必要完成許多聯接。

這是一個合理的方式去完成這項任務?可能是我忽略的任何不可預見的或長期的後果?

+0

JNK是正確的(雖然沒有SQL中的連接優化 - RDBMS是。雖然細節)。對於我們的發票申請,我們有類似的問題,但那裏的「歷史」表是發票表的精確副本,還有一些附加字段(歷史PK,時間戳等)。容易'插入歷史選擇空,現在(),...,我*發票我'* – Konerak 2012-04-11 19:14:30

回答

5

性能的說法是無稽之談 - 你做的更少JOIN s,但RDBMS針對JOIN進行了優化。

但是,您可能會從服務器拉出批次以上的以上的數據,而這些數據不能被優化掉。

您還可能有一致性問題。在不同表格中複製同一項目的數據會導致出現不一致的能力。如果修訂記錄和物品記錄對於formatauthor有不同的值?你怎麼知道哪一個是正確的? Articles中的content與任何修訂版本不匹配會怎麼樣?

你真的應該正常化這個。我會將一個CurrentRevision字段添加到您的Articles表中以鏈接到當前版本,並且您應該在Revisions表中將ArticleID鏈接到一起。

+0

謝謝你在這方面脫穎而出。我現在意識到,保持一致性的代碼可能最終會成爲更多的工作。 – trinth 2012-04-11 20:13:57

+0

CurrentRevision字段是否真的有必要?這意味着每次創建或編輯一篇文章時需要3次調用DB: 1.創建文章 2.參考步驟(1)的文章創建修訂版 3.使用步驟(2)的修訂版更新article.current_revision – trinth 2012-04-11 20:55:43

+1

@trinth雖然這些人都沒有理由需要單獨打電話。您可以進行一次調用來插入文章和參考,您只需正確處理代碼中的ID值即可。 – JNK 2012-04-11 20:59:17

7

如果你關心你的數據,在「非規範化」的情況下你不會得到更少的代碼 - 你必須強制Revision中的最後一行總是匹配Article中的副本。這在併發環境中實際上並不是微不足道的 - 你必須非常仔細地進行鎖定!

(如果你選擇RevisionArticle不包含相同的副本,那麼這是更糟糕的 - 你將不能夠依靠DBMS爲強制執行Revision主鍵!)

隨着DBMS功能足夠強大,您可以擁有自己的蛋糕並將它吃掉 - 例如,Oracle物化視圖可以爲您預加入數據,而無需對實際數據模型進行非規範化。

即使您沒有這樣一個DBMS,也只有在您具有測得的數據的實際數據量後才考慮非規範化。是的,連接可以是昂貴的,但他們貴在你的特定情況?只有測量可以說明。


順便說一句,可以考慮使用標識關係/自然關鍵是這樣的:

enter image description here

revision_no單調,你在給定的文章添加修改的增長。

Revision PK下面的B-Tree結構使得找到給定文章的最新(或任何!)修訂版非常高效。除非您的問題中沒有顯示備用密鑰,否則您也可以使用Revision和(在Oracle下)甚至壓縮聚簇索引的前沿,因此重複article_id的空間開銷將被廢止。

+0

我從你的評論中學到了很多東西,我將會用標準化的選項進行討論。我選擇其他答案作爲「解決方案」,不過因爲他的建議是我最終使用的。 – trinth 2012-04-12 16:00:16

+1

@trinth注意'Article.CurrentRevision'。據推測,「修訂版」已經在某個領域訂購了,而最後的修訂版可以從該訂單自然推斷出來。因此,「CurrentRevision」不會向系統引入任何新信息,它只是複製現有的信息 - 它是**冗餘**,並且冗餘會導致修改異常。你甚至沒有從它的存在中獲得任何性能優勢(在B樹中,搜索MAX與搜索具體值一樣快)。只有當「最後」和「當前」修訂意味着不同的事情時,它的存在纔是合理的。 – 2012-04-12 16:26:45