2010-10-25 37 views
22

我想知道如果您有一個網站需要不同領域的十幾種不同類型的列表(商店,餐廳,俱樂部,酒店,活動),是否有創造與列的表定義像這樣
例店鋪:有多列與靈活抽象表的單個固定表

shop_id | name | X | Y | city | district | area | metro | station | address | phone | email | website | opening_hours 
類似

或者更抽象的方式來這樣:

object_id | name   
--------------- 
1   | Messy Joe's 
2   | Bate's Motel 

type_id | name 
--------------- 
1  | hotel 
2  | restaurant 


object_id | type_id 
--------------- 
1   | 2 
2   | 1 

field_id | name   | field_type 
--------------- 
1  | address  | text 
2  | opening_hours | date 
3  | speciality  | text 

type_id | field_id 
--------------- 
1  | 1 
1  | 2 
2  | 1 
2  | 3 

object_id | field_id | value 
1   | 1  | 1st street.... 
1   | 3  | English Cuisine 

當然它可以是更抽象的,如果值的是預定義的(例如:菜庫侖d有自己的列表)

如果我採用抽象的方法,它可以非常靈活,但查詢將會更復雜,有很多連接。 但我不知道這是否會影響性能,執行這些'更復雜'的查詢。

我很想知道這兩種方法的優點和缺點。我可以爲自己想象,但我沒有經驗來證實這一點。

+2

謝謝。您可能對** [此問題/答案](http://stackoverflow.com/questions/4304217/database-schema-which-can-support-specialized-properties/4359193#4359193)**感興趣。 – PerformanceDBA 2010-12-24 00:53:02

回答

71

一些問題需要加以澄清和解決纔可以進入一個合理的討論。

預必要的分辨率

  1. 標籤
    在要求精度的行業,重要的是,我們使用精確的標籤,以避免混亂,這樣我們就可以不必使用交流冗長的描述和限定詞。

    您發佈爲FixedTables的內容是未標準化。公平的說,它可能是第三範式的嘗試,但實際上它是一個平面文件,非標準化(非「非規範化」)。您發佈爲AbstractTables的內容準確地說是實體屬性值,它差不多,但不完全,第六正常形態,因此比3NF更加標準化,假設它是做正確的,當然。

    • 的Unnormalised平面文件是不是「去歸一化」,這是座充滿(沒有做任何事情去除重複的組和重複的列或解決依賴關係)和空值,它在很多方面表現異常,並且防止併發性。爲了達到Denormlaised,它必須首先進行標準化,然後由於一些很好的原因標準化退出一點。由於它首先不是標準化的,因此不能非規範化。這簡直是​​非正常化。

    • 它不能說是「表現」的非正規化,因爲作爲一個表現豬,它是性能的對立面。那麼,他們需要缺乏形式化設計的理由],而「爲了表現」就是這樣。即使是最小的正式審查揭露了這種歪曲事實(但很少有人能夠提供,所以它仍然是隱藏的,直到他們讓外部人解決,你猜對了,這是巨大的性能問題)。

    • 標準化結構的性能遠優於非標準化結構。更多的標準化結構(EAV/6NF)比標準化程度更低的結構(3NF/5NF)表現更好。

    • 我與OMG小馬的推力同意,但不是他們的標籤和定義

    • ,而不是說「不‘denormalise’除非你有」,我是說,「正常化忠實地,期間''如果有性能問題,您還沒有正確標準化'
  2. 維基
    條目重新範式和規範化是一個完整的笑話。具體來說,定義是不正確的;他們混淆了範式;他們對標準化的過程毫無頭緒;並且他們同樣重視早已被揭穿的荒謬或可疑的NFs。結果是,維基添加到了一個已經很混亂且很少理解的主題中。所以不要浪費你的時間。

    但是,爲了進步,沒有那個參考提供障礙,讓我這麼說。

    • 3NF的定義是穩定的,並沒有改變。
    • 3NF和5NF之間存在很多NF的混淆。事實是,這是過去15年來發展的一個領域,許多組織,學者和供應商以他們的產品有限,跳過創建一個新的「範式」來驗證他們的產品。所有服務商業利益和學術不健全。 3NF在其原始未受攻擊的狀態下打算並保證某些屬性。
    • 總數是,5NF是今天,3NF是15年前的意圖,你可以跳過商業笑話和12個左右的「特殊」(商業和僞學術)NF之間,一些其中在Wiki中被識別出來,甚至在混亂的條件下被識別出來。
  3. 由於您已經能夠在您的文章中瞭解和實施EAV,因此您不會理解以下內容。當然,真正的關係模型是先決條件,強鍵等第五範式是,由於我們跳過第四:

    • 第三範式
      • 這簡單明確的方面是,在每個表的每個非鍵列具有1間:: 1的關係表中的主鍵,
      • 並沒有其他非鍵列
    • 零數據複製(結果,如果規範化是進展艱難ntly;沒有通過單獨的智能或經驗實現,或通過努力實現它作爲一個目標沒有正式的過程)
    • no更新異常(當您更新列的某處,您不必更新位於其他地方的同一列;列存在於一個且僅有的一個地方)。
  4. 第六範式當然是第五範式,再加上:

    • 丟失的數據(列)消除。這是Null Problem(也稱爲處理缺失值)的真正解決方案,結果是一個沒有空值的數據庫。 (可以用5NF的標準和零替代品完成,但這不是最佳的。)如何解釋和顯示缺失值是另一回事。
  5. EAV VS第六範式
    所有數據庫我已經寫了,除一人外,都是純5NF。我曾與(管理,修復,增強)兩個EAV數據庫合作過,並且我實現了一個真正的6NF數據庫。 EAV是6NF的鬆散實施,通常由對標準化和NF認識不足的人完成,但他們可以看到EAV的價值,並且需要EAV的靈活性。你是一個完美的例子。不同之處在於:因爲它很寬鬆,而且由於實現者沒有一個忠實的參考(6NF),所以他們只實現他們需要的東西,而且他們全都用代碼編寫;最終成爲不一致的模型。

    而純6NF的實現確實有一個純粹的學術參考點,因此它通常更緊密和一致。典型地,這示出了在兩個可見元素:
    • 6NF具有目錄包含元數據,並且一切都在元數據,而不是代碼中定義。 EAV沒有一個,一切都在代碼中(實施者跟蹤對象和屬性)。顯然,目錄簡化了列,導航的添加,並允許組建實用程序。
    • 6NF當被理解時,爲The Null Problem提供了真正的解決方案。 EAV實施者,因爲他們缺少6NF上下文,在代碼中處理丟失的數據,不一致或更糟,允許數據庫中的空值。 6NF的實現者不允許Nulls,並且一致且優雅地處理丟失的數據,而不需要代碼構造(對於Null處理;當然,你仍然需要編寫丟失數據的代碼)。
      。例如:
      例如。對於具有目錄的6NF數據庫,我有一組proc將會[重新]生成執行所有SELECT所需的SQL,並且我爲所有用戶提供5NF中的Views,因此他們不需要知道或理解底層6NF結構。他們被趕出目錄。因此更改非常簡單且自動化。由於沒有目錄,EAV類型會手動執行此操作。

現在,我們就可以開始

討論

「,當然也可以是如果 價值的是預定義的(例子更加摘要: 特色可以有自己的自己 列表)」

當然。但不要太「抽象」。保持一致性並以與其他列表相同的EAV(或6NF)方式實施此類列表。

「如果我參加了抽象的方法就 可以很靈活,但查詢將 是有很多連接。 的更復雜,但是我不知道這是否會影響 性能,執行這些'更多 複雜'查詢。「

  1. 加盟是行人在關係數據庫中。問題不在於數據庫,問題在於SQL在處理連接時特別麻煩,尤其是複合鍵。
  2. EAV和6NF數據庫有多個連接,這就像行人,不多不少。如果你必須手動編碼每個選擇,確定,繁瑣變得非常麻煩。
  3. 整個問題可以通過(a)用6NF去在EAV和(b)實施目錄,從中可以(C)產生的所有基本的SQL被淘汰。也消除了一整類錯誤。
  4. 加盟莫名其妙地有成本是一個常見的神話。完全錯誤。連接是在編譯時執行的,沒有任何實質性的東西來「花費」CPU週期。問題是正在連接的表的大小,而不是這些相同表之間的連接的成本。以正確的PK⇢FK關係連接兩個具有數百萬行的表格,每個表格都具有適當的索引(父[FK]側爲唯一;子項側爲唯一)是即時的; ;兒童索引不是唯一的,但至少領先的列是有效的,它比較慢;沒有有用的指數,當然這很慢。與加入成本無關。在返回多行的情況下,瓶頸將是網絡和磁盤佈局;不是加入處理。
  5. 因此,您可以按照自己喜歡的方式獲得「複雜」,不需要任何成本,SQL可以處理它。

我很想知道什麼是 了起來,這兩種方法的缺點。 我可以爲自己想象,但我 沒有經驗來確認 這個。

  1. 5NF(或3NF對於那些誰沒有取得進展)是最簡單,最好的,在執行方面,易用性(開發者以及用戶),維修。缺點是,每次添加列時,都必須更改數據庫結構(表DDL)。這很好,但有一些情況,但在大多數情況下,由於變更控制的原因,相當麻煩。其次,您必須更改現有代碼(處理新列的代碼不會計算在內,因爲這是必須的):實施好的標準時,將其最小化;如果他們缺席,範圍是不可預測的。

  2. EAV(這是您發佈的內容),允許添加列而無需DDL更改。這是人們選擇它的唯一原因。 (處理新列的代碼不計算,因爲這是一個必要的)。如果實施得好,它不會影響現有的代碼;如果沒有,它會的。但你需要支持EAV的開發人員。當EAV執行得不好時,它比惡劣的5NF糟糕得多,但並沒有比非標準化更糟,這是大多數數據庫所存在的(被錯誤地表述爲「對性能非規範化」)。當然,更重要的是(比在5NF/3NF中)擁有強大的事務上下文,因爲列更分散。同樣,保留聲明性參照完整性也是至關重要的:我所看到的混亂在很大程度上是由於開發人員刪除DRI,因爲它變得「太難以維護」,結果就像你想象的那樣,一個數據母親在整個地方堆滿了重複的3NF/5NF行和列。不一致的Null處理。

  3. 假設服務器已按照預期目的進行了合理配置,性能沒有差別。 (好吧,只有在6NF纔有可能進行特定的優化,這在其他NF中是不可能的,但我認爲這超出了本主題的範圍。)而且,EAV做得不好可能會導致不必要的瓶頸, Unnormalised。

  4. 當然,如果你使用EAV,我建議更多的手續;購買完整的小費;與6NF一起去;實施目錄;生成SQL的實用程序;意見;一致地處理缺失數據;完全消除空值。這可以降低您對開發人員質量的脆弱程度;他們可以忘記EAV/6NF深奧的問題,使用視圖,並專注於應用邏輯。

請原諒。

+4

哇,謝謝大家的回覆,非常有趣。當然,我需要重讀幾遍,但是我想問一下如何掌握6NF最可靠的資源?維基百科和谷歌的結果沒有那麼有用。你在哪裏/你是如何學習的? – Moak 2010-10-26 07:11:55

+8

謝謝你的友好的話。沒有這樣的來源。有很好的教科書。網上提供的信息(對於任何事物,不僅僅是這個狹窄的主題)是垃圾維基是一個平庸的研究。你得到你想要的。一個好的Uni的正規IT學位是最好的開始。正如你所知,掌握來自與主人合作。 AFAIK只有另一家公司提供這個級別的掌握這個問題:他們出售它作爲一種產品;我把它當作一種服務來銷售,因爲我相信客戶必須真正瞭解它,擁有它,而不是將它鎖定在產品中。 – PerformanceDBA 2010-10-26 09:12:51

+2

Where/How。那麼,我做了以上所有的事情,我非常感謝我擁有的優秀教師。我每年改善大約四個數據庫,對於大型銀行而言,這是我的激情/專業。如果我在這裏多說一點,這將是不正確的。如果你對更多細節感興趣,請追查我:profile⇢website⇢email。我會自由回答你的問題。乾杯。 – PerformanceDBA 2010-10-26 09:29:50

2

「抽象」方法更好地稱爲「規範化」,看起來像第3範式(3NF)。

另一個被稱爲「非規範化」,並且可以是一個有效的性能選項......當您使用規範化方法遇到速度問題時,而不是之前。

+0

所以你的意思是應該建立規範化的方法,如果性能真的是一個問題,那麼要麼升級硬件,要麼更改所有代碼並創建新表?對不起,我不確定你在告訴我什麼...... – Moak 2010-10-25 05:02:31

+0

@Moak:是的。爲了在沒有需要的情況下進行非規範化的方法是不成熟的優化。 – 2010-10-25 05:06:29

+0

由於我不知道這些正常形式,你能否建議我是否應該查看第一,第二,第四,第一或其他正常形式? – Moak 2010-10-25 05:09:38

1

你如何在代碼中表示清單?我猜Listing作爲超類型,與Shop,Restuarant等作爲子類型?

假設是這樣,這是如何將子類型映射到關係數據庫的情況。通常有三種選擇:

  • 選項1:每個亞型單個表, 與 每個表重複共同屬性(姓名,身份證等)。
  • 選項2:所有對象單個表(您單表的方法)
  • 方案3:表的父,併爲每個亞型

有沒有普遍正確的解決方案。我的選擇一般是從選項3開始;它提供了一個可操作的intituitive結構,很好地標準化並且可以很容易地擴展。它意味着用於檢索每個實例的單個連接 - 但RDBMS對於連接進行了充分優化,因此它在實踐中並不會真正導致性能問題。

如果其他表需要引用所有超類型實例(外鍵擴散),則選項2可以更好地執行查詢(無連接),但會導致問題。

選項1第一眼看來是最高性能的,儘管有兩個注意事項:(1)它沒有改變的靈活性。如果添加新的子類型(以及不同的屬性),則需要更改表結構並將其遷移。 (2)效率可能不如看起來好。由於表格人口稀少,一些數據庫不會特別有效地存儲它。因此,它的效率可能比選項1低 - 因爲查詢引擎可以加入的速度比搜索膨脹的稀疏表空間要快。

選擇哪種方法真正歸結爲了解問題的細節。我建議閱讀一下選項:this article是一個很好的開始。

心連心

8

在你的問題中,你同時提出了至少兩個主要問題。這兩個問題是E-A-V和gen-spec。

首先,我們來談談E-A-V。你的最後一張表(object_id,field_id,value)本質上是一個E-A-V。E-A-V存在上行空間,而E-A-V則存在下行空間。好處是結構非常通用,幾乎可以容納任何描述幾乎所有主題的數據。這意味着您可以進行設計和實施,不需要數據分析和對主題的理解,也不用擔心錯誤的假設。不利的一面是,在檢索時,您必須執行在構建數據庫之前跳過的數據分析,以便提出任何含義的查詢。這比檢索效率要嚴重得多。但是,您也將在檢索效率方面遇到可怕的問題。只有兩種方式可以瞭解這個陷阱:通過它來實現它,或者從那些已經有過的人那裏讀到它。我建議閱讀。

其次,你有一個gen-spec的情況。你的表(object_id,type_id)捕獲一個gen-spec(泛化專業化)模式,以及相關的表格。如果我不得不在酒店和餐館之間進行概括,我可能會把它稱爲「公共住宿」或「場地」。但我不確定我是否理解你的情況,而且你可能會開車比這兩個名字所暗示的更普遍。畢竟,你在列表中包含了「事件」,而事件並不是我腦海中的一種場合。

我已經將其他人引用到以前的回覆中關於gen-spec和關係模型的讀物上。
When two tables are very similar, when should they be combined?

但我毫不猶豫地向您發送相同的方向,因爲它要拿出數據的關係模型構建數據庫之前並不清楚給我。數據主體的關係模型和相同數據的E-A-V模型幾乎完全相互矛盾。在我看來,您必須先做出選擇,然後才能在關係數據模型中探索如何表達gen-spec。

1

當你開始需要大量不同的實體(甚至在...之前)時,nosql解決方案將比任一選擇都簡單得多。 只需將每個實體/記錄與您需要的確切字段一起存儲即可。

{ 
    "id": 1, 
    "type":"Restaurant", 
    "name":"Messy Joe", 
    "address":"1 Main St.", 
    "tags":["asian","fusion","casual"] 
}