2012-11-27 56 views
0

在我的網站我有一個論壇,你可以啓動一個線程,迴應一個,刪除自己的帖子,報告他人的信息等簡單的查詢與簡單的數據庫

我決定做一個抽象和創建一個名爲activity的表,它將存儲user_id,time(每個活動都有相同的字段)以及活動類型(線索,響應,報告,刪除)和(對應於相應表的id) 。

開始時,這似乎是一個好主意,因爲它有助於避免冗餘,並且可以更容易查找某個用戶完成的操作,而無需詢問每個表。但與此同時,這種抽象會導致更復雜的查詢(例如幾乎每個簡單的查詢都必須使用INNER JOIN),現在我遇到了更復雜的查詢問題。

所以我的問題是:我做出了正確的決定嗎?即使它導致非常昂貴的查詢,在真實生活環境中如何擁有一個完美的數據庫如此重要?

+1

」正常化,直到它傷害,反規範化,直到它工作。「 –

回答

1

關係數據庫系統的要點是關聯數據(通過在正確的表中分隔實體),通過這樣做來引入連接。這是正常的,也是一種很好的數據庫設計技術

很多數據庫初學者試圖避免連接並添加來自各個實體的屬性,以避免必須進行INNER連接,但這不是一種適當的技術,並且長期來說會咬你。加入是有原因的,應該在需要關聯數據時使用。

在你的例子中,你本質上是創建一個「日誌」文件。應用程序中的活動僅僅是用戶正在做的事情的日誌。問問你自己,一篇文章日誌,一份報告日誌,一份刪除日誌,一份日誌,還有許多日誌表或者一個帶有referenceID的簡單日誌表,用戶發起了什麼活動(這個實際上是FK)。答案是你想要一個包含外鍵的日誌表讓你知道用戶發起了什麼(刪除,添加,標誌等)。

你想問自己的問題是,爲什麼當用戶只是想要獲取這些數據時顯示活動信息。您可以隨時保持這些數據正常化,但只在需要時才選擇。我不明白你爲什麼加入這個活動表。

+0

是的,「這不是一個合適的技術,並且會長期咬你」,我想這是真的。這就像在優秀設計和簡單性之間取回數據一樣,在這種情況下,第一種可能會獲勝。 爲了回答你的問題:在活動表中,每個活動的'time'和'user_id'被存儲,所以如果我想向用戶展示它,我必須使用'INNER JOIN'。 無論如何,謝謝你的回答! – federicot

1

我想我會朝着與3 - 5年前相同的方向前進,但現在我會傾向於採用更簡單,更平坦的數據庫設計來描述您所描述的活動,而不是採用更標準化的方法。

我對CQRS和Task Driven UI的使用和理解確實幫助我意識到這一點 - 儘管它可能與您的情況無關。

本質上,我用來優化我的數據庫,以便插入,更新和刪除非常高效,但這會導致連接很多表以進行簡單選擇。問題是80%的時間,用戶想要選擇。因此,優化我的數據庫結構,以確保用戶在大多數情況下所做的工作確實有助於提高應用程序的整體性能,並且以我的觀點來看,系統的維護和可擴展性。

我對你的應用程序以及你想做什麼做了一些假設,但對我而言,一個活動表聽起來像是可以從隊列中提供並由單獨的工作進程/線程構建的東西這是監視工作項的隊列。當找到這些工作項目(命令)時,工作進程將平整數據並更新適當的活動表。當你去查詢你的活動表時,你基本上會做一個簡單的SELECT * FROM ACTIVITY(儘管我不建議SELECT *查詢 - 命名你的列)。因此,您可以在插入/更新活動表格時發揮作用,但您的選擇表現非常好。

我希望這會有所幫助。

1

我不確定你的問題是什麼你的目的是分裂所有活動的共同特徵,以及複雜查詢給你帶來麻煩的方式。

活動類型(線程,響應,報告,刪除)的描述看起來像是類型和子類型的經典案例,也就是類和子類。這種情況有兩種經典設計模式,稱爲單表繼承和類表繼承。這兩種設計模式都有標籤。還有另一種設計模式,即共享主鍵,可用於與類表繼承一起使用。

從STI到CTI的轉變確實涉及到一些表格分解,它與您描述的分解類似。 SPK的使用避免了每個專用子類表需要單獨的id字段,並且也避免了對單獨類型字段的需要。這可能會導致比您最終掙扎的查詢更簡單的查詢。沒有看到這些查詢,這是不可能知道的。

值得注意的是,從獲得符合任何標準正常形式2NF到5NF的意義上來說,這種分解不是「標準化」。但是這些正常的形式關注更新的簡單性,而不是簡單的查詢。

一個好的設計是考慮到數據將被使用的方式。有時候我們會一路學習。我不知道什麼是完美的設計。我認爲我們總是參與權衡。 「