建構盡可能多的外鍵是一種好習慣嗎?
例如,有三個表:
players
、dungeons
和instances
。一個
player
有很多dungeons
,一個dungeon
有很多instances
,就像一個著名的魔獸世界遊戲。每個player
都有一個dungeon_id
作為外鍵,每個dungeon
都有一個instance_id
作為外鍵。那將是一種足夠的極簡主義方法。player
每一個都instance
可以通過dungeon
表訪問。這將減少 1 列,但查詢時間更長。另一種方法是作為外鍵添加
player_id
到表中。instances
現在玩家可以直接從instances
表中查詢。更短的查詢,但外鍵多一列。從長遠來看,哪種方法更好?在實踐中,似乎在邏輯上可能的任何地方都添加外鍵會更容易。但是這不會導致更緊密的耦合併使程式碼更難重構嗎?
理想情況下,實體不應該有外鍵,應該被認為是主人。所以
player
,dungeon
並且instance
是擁有與他們自己的特徵相關的資訊/屬性/欄位的大師。您可以為Enitity-Relations提供一個單獨的表。因此,您將擁有player_dungeon
anddungeon_instance
(根據 PS,兩者都是一對多)。在這裡,如果你想知道instances
屬於一個player
,你需要加入這兩個表。現在出現了著名的辯論:規範化與非規範化。第一種方法是書本上的,並且會奏效。但是隨著表的增長很難擴展(儘管有適當的索引)。因此,您嘗試根據這些表上發生的查詢量對上述解決方案進行非規範化。
player
每一個都instance
可以通過dungeon
表訪問。由於您在此處指定了一個查詢,我假設這是一個頻繁查詢(瓶頸)。如果有很多這樣的查詢,你可以有另一個關係表
player_instance
。現在我們已經解決了延遲的問題,但產生了一個更大的問題:一致性:現在有兩種方法可以找到
instances
屬於 a 的player
。一種是直接按player_instance
表,另一種是通過player_dungeon
和連接dungeon_instance
。我們必須始終從這兩種方法中得到相同的答案。為了確保我們現在需要讓我們的寫入受到影響。如何?
- 在添加每個玩家-地牢映射時,除了進入我們的
player_dungeon
表之外,我們還需要插入到player_instance
表中(我們必須查詢dungeon_instance
以查看映射到該特定地牢的所有實例)。- 在添加新
dungeon_instance
玩家時,我們需要將所有現有玩家映射到我們映射到特定地牢的實例。聽起來不太好,是嗎?我們還沒有完成。所有這些操作都應該是原子的(即在事務中),否則會在短時間內出現不一致。
最後,我們需要做出取捨。您想讓您的數據庫讀取速度變慢還是寫入受到影響?您是否需要使您的系統響應/可用或一致?決定權在你。
詳情請閱讀CAP 定理。