2011-09-07 174 views
1

我有一個設計問題與db非規範化。
我正在製作一個相對較大的數據庫,需要儘可能優化它。mysql數據庫鏈表非規範化

這是一個非常簡化的問題模型。
圖片中的所有表格都鏈接在一起,並且使用規範化數據庫來獲取來自特定國家的所有用戶,例如我必須加入所有表格。那是cca 250個國家x cca 12000個城市x cca 625000個地區x?地址x?用戶...總之,這是一個很多的加入,這需要很長的時間。

我想要做的是在user表中使country_id冗餘,因此我可以在沒有任何連接的情況下獲得相同的查詢。

問題是,在這樣一個模型中保持一致性的最佳實踐是什麼(使用MySql btw)?

單向和可能最快的方法是在插入/更新/刪除數據時確保應用程序級別的一致性。

其他是存儲過程,我真的沒有看到任何優勢。只有直接調用才能確保一致性。如果你想在沒有程序的情況下進行一些修改,一致性就會中斷。

我也一直在尋找觸發器......不太清楚如何實現它,以及我會在性能上獲得多少收益。

無論如何,最好確保數據庫級別的一致性。

有什麼建議嗎?

Sample model

回答

0

這不是真的很多加盟假設你是不是要反規範化您的所有數據。另一方面,大多數人只需要一個地址表,或者(gasp!)將地址信息保存在用戶表中。您希望支持多少個國家/城市,以及有多少用戶?

+0

正如我所說,這是一個簡化的模型。這種結構是必要的。至於記錄的數量,你必須能夠在世界的任何地方進行註冊,所以帖子中的數字幾乎可以召喚它。有多少用戶很難預測......無論如何它必須能夠處理幾十萬用戶。另外值得一提的是,很多查詢都是針對特定國家/地區的,因此一次又一次地加入所有內容似乎太多了 – ZolaKt

+0

然後在users表中有一個countryID,一個StateID和一個......等等。除非您需要水印一些複雜的商業目的,我強烈建議避免它。 –

+0

好的,但問題是如何確保一致性是一個這樣的模型,而不是真正的使用它。 – ZolaKt

4

所有的圖片中的錶鏈式,並用標準化 數據庫獲得例如所有來自特定國家的用戶我 必須參加所有表。

您必須加入所有表格,因爲您使用代理鍵(id號),而不是因爲表格是「標準化」的。使用像id號這樣的代理鍵與標準化沒有任何關係。

自然鍵和外鍵約束是您解決問題所需的全部。

查看工作原理的最簡單方法是從完整數據開始,並完全倒退。假設所有的數據都是正確的。

addr_id street   street_num  region city   country 
-- 
1  Babukiaeeva  3a    10000  Zagreb  Croatia 
2  Riva    16    51000  Rijeka  Croatia 
3  Andrije Hebranga 2-4    10000  Zagreb  Croatia 
4  Andrijeviaeeva 2    110000  Zagreb  Croatia 

錄製像「地區‘10000’與城市‘薩格勒布’在全國‘克羅地亞’相關」的事實,創建一個新表,並從該查詢填充它。

SELECT DISTINCT region, city, country from addresses; 

表看起來是這樣的。

Table: regions 
Primary key: {region, city, country} 

region city  country 
-- 
10000 Zagreb Croatia 
51000 Rijeka Croatia 
110000 Zagreb Croatia 

然後設置外鍵引用。

ALTER TABLE addresses 
ADD CONSTRAINT FOREIGN KEY  (region, city, country) 
       REFERENCES regions (region, city, country); 

錄製像「城市‘薩格勒布’是在國家「克羅地亞」的事實,創建一個新的表,從該查詢填充它。

SELECT DISTINCT city, country from regions; 

表看起來像這樣。

Table: cities 
Primary key: {city, country} 

city  country 
-- 
Zagreb Croatia 
Rijeka Croatia 

然後設置外鍵引用。

ALTER TABLE regions 
ADD CONSTRAINT FOREIGN KEY  (city, country) 
       REFERENCES cities (city, country); 

對國家重複。表格中的國家,城市和地區都非常重要,所以他們在5NF。 (他們不能有任何非關鍵的依賴關係,因爲他們沒有非關鍵列。)在像大部分歐洲一樣的大面積的情況下,地址表很可能也在5NF。

查詢性能的條件可能會圍繞您當前的模式運行,因爲它不需要連接。

您可能會想要使用ON UPDATE CASCADE;雖然你可能想要級聯刪除而不是

+0

這是一個完全冗餘的方法。我認爲最好不要因爲性能原因使用組合鍵。但我仍然不相信這是實現它的方式,因爲它複製了一切/無處不在。我認爲生病時最終會採用物化視圖方法 – ZolaKt

+0

「冗餘」是關係理論中的一個技術術語;它與存儲外鍵沒有任何關係。 (這就是外鍵的用途。)*這些*組合鍵消除了所有聯接。在大多數情況下,這種模式將比3或4個連接執行得更快。我已經運行了這樣的測試,執行速度提高了200倍。在提交此模式或實體化視圖之前,您應測試性能。 –

+0

是的,它們消除了連接,這是正確的......但是它們複製了大量數據(每個表格中的所有「較低」鍵),並且存在前置問題。合成鍵具有較低的性能(至少在MySql中),所以我認爲它更好地介入一個新增的ID,並使合成UNIQUE成爲可能。但是,無論如何:我更喜歡這種物化視圖方法。仍然存在持續性問題,但至少在「原始」表中沒有冗餘 – ZolaKt

1

首先 - 它真的太慢了​​嗎? 你試過了嗎? 你有一個應用程序在哪裏轉儲所有用戶(爲什麼?),或者你現在或時間只抓取一個/幾個用戶。由於您在所有這些ID上都有主鍵,因此檢索速度應該不會那麼慢,畢竟背景中存在B樹。其次,我不會在街道號碼處規範化,你很難從中獲得任何好處,並且你最終可能會在用戶和地址之間產生幾乎1:1的關係。因此,將您的街道號碼移動到客戶端,或者甚至可以將整個地址表移動到用戶。我可能會將地區表也移到客戶端(這些是城市地區?),並最終得到用戶,城市和國家的表格。

然後你會有兩個連接,如果這仍然太慢,你可以把冗餘的國家關鍵字(或者,因爲我們正在反規範 - 國名)在用戶。我會使用觸發器來保持完整性,更確切地說,您必須編寫以下內容:插入和更新觸發器(更新需要僅在regionId/cityId更改時觸發)以及國家/地區的更新觸發器(如果您的國家/地區名稱爲在不太可能發生國家名稱變化的情況下用戶表)。性能方面,你不會獲得,但會失去觸發器,但我想用戶表上的插入和更新並不是很頻繁,以至於你會注意到它。

最後,由於您沒有詳細解釋您(web?)應用的性質和規模,只是提醒您可能還想考慮/在關係數據庫之外考慮其他優化技術(緩存, sql dbs等)。

+0

地址用於幾件事情,不僅僅是用戶......所以我不能將它移動到用戶表中。是的地區是城市地區。他們也應該保持獨立,因爲他們在很多地方(比城市更多)使用。好吧,我使用提到的物化視圖方法使用觸發器。 – ZolaKt