2012-01-18 55 views
0

我正在使用PHP和PostgreSQL重建應用程序(此處爲單獨的開發人員)。對於大多數數據,我使用每個屬性具有多個列的表進行存儲。但是,我現在開始構建內容存儲的一些表格。這種情況下的內容是多個部分,每個部分包含不同的數據集;一些數據是常見的,共享的(以及外鍵)和其他數據是非常獨特的。在應用程序的當前迭代,我們有一個表的結構是這樣的:EAV與基於列的數據組織對於我的數據

id | project_name | project_owner | site | customer_name | last_updated 
----------------------------------------------------------------------- 
1 | test1  | some guy  | 12 | some company | 1/2/2012 
2 | test2  | another guy | 04 | another co | 2/22/2012 

現在,這個工作 - 但它很難得到維護的幾個原因。添加新列(很少發生)需要修改數據庫表。審計/歷史記錄追蹤需要一個單獨的表格,用於將附加信息映射到主表格 - 如果主表格已更改,還需要進行修改。最後,有很多列 - 在一些表中超過100列。

我一直在頭腦風暴的替代方法,包括把一張大桌子分成幾個小桌子。這引入了我認爲也會導致問題的其他問題。

我目前正在考慮的方法似乎被稱爲EAV模型。我有一張如下所示的表格:

id | project_name | col_name | data_varchar  | data_int | data_timestamp | update_time 
-------------------------------------------------------------------------------------------------- 
1 | test1  | site  |     | 12  |    | 1/2/2012 
2 | test1  | customer_name | some company |   |    | 1/2/2012 
3 | test1  | project_owner | some guy  |   |    | 1/2/2012 

...等等。這有一個好處,我永遠不會更新,總是插入。數據不會被覆蓋,只會被添加。當然,桌子最終會變得相當大。我有一個'索引'表列出了項目,並用於引用'數據'表。不過,我覺得我錯過了這種方法的一些大事。它會縮放嗎?我原本想做一個簡單的鍵 - >值類型表,但意識到我需要能夠在表中有不同的數據類型。這似乎是可管理的,因爲我使用的數據庫抽象層將包含一個從正確列中選擇數據的類型。

我是否爲自己做了太多工作?我應該堅持一個簡單的桌子和一大堆列嗎?

+0

我可能會嘗試使用第一種解決方案來儘可能多地識別公共列,並使用外部索引或完全離開SQL解決方案並轉向NoSQL文檔存儲(如MongoDb,CouchDb等)。我真的不喜歡第二種選擇,這是災難性的。 – mobius 2012-01-18 22:47:17

+1

Postgres有一個很好的擴展名爲hstore,這是一個比EAV更好的解決方案。 http://www.postgresql.org/docs/current/static/hstore.html它是Postgres中的NoSQL;) – 2012-01-18 23:19:42

回答

0

移動你整個結構EAV會導致大量的向下行的問題,但它可能會以來經常外鍵關係和嚴格的數據類型化了你的問題的審計跟蹤部分是可以接受的可能隨時間而消失呢。您甚至可以使用觸發器和存儲過程自動生成審計表。

但是,請注意,重建舊版本的記錄對於EAV審計跟蹤而言並不重要,並且需要相當數量的應用程序代碼。數據庫將無法自行完成。

你可以考慮另一種方法是將所有數據(新舊記錄)存儲在相同表。您可以在同一個表中包含審計字段,並在不需要時保留NULL,或者將表中的某些行保存爲「當前」,並將與審計相關的字段保存在另一個表中。爲了簡化您的應用程序,您可以創建一個僅顯示當前行並針對該視圖發出查詢的視圖。

您可以使用連接的表繼承模式來完成此操作。通過連接表繼承,可以將常見屬性與「類型」列一起放入基表中,並且可以根據類型連接到其他表(具有同樣的主鍵也是外鍵)。許多數據映射器模式ORM對這種模式有本地支持,通常稱爲「多態」。

你也可以使用PostgreSQL的原生table inheritance mechanism,但請注意注意事項!

+0

這聽起來像是要走的路。無論哪種方式聽起來都很「髒」,但在有關EAV的其他問題已經提出之後,這更有意義。 – kagaku 2012-01-19 15:12:26

+0

我認爲最好的方法是將所有版本歷史記錄存儲在與當前活動記錄相同的表格中,無論您是否使用其他一對一表格來查看更多字段。您的活動記錄是'max(修訂版)',而舊版本是較低版本的修訂版。你可以通過花哨的索引或類型標誌來加速公共訪問情況。畢竟,從ER角度看,主動和修改的記錄是相同的實體。 – 2012-01-19 15:41:17

3

我的建議是,如果你可以避免使用EAV表,那就這樣做。他們往往是性能殺手。他們也很難正確查詢,特別是報告(是的,讓我加入到這張表中未知的次數,以獲取我需要的所有數據,順便說一句,我不知道我有什麼列可用所以我不知道報告需要包含哪些列),並且很難獲得確保數據完整性所需的數據庫約束(例如,如何確保填充所需的字段),並且可能會導致你使用錯誤的數據類型。從長遠來看,定義存儲所需數據的表格要好得多。

如果您確實需要這些功能,那麼至少應該查看一下NoSQL數據庫,這些數據庫對於這類未定義的數據更加優化。