天天看點

關系資料庫設計中,用中間表好還是直接設定主外鍵關聯好?

有人會對資料庫有這樣的疑問:

因為大多數的資料庫教程上都是告訴你關系資料庫如何去建立1:1、1:N和N:M的資料庫關系,但我發現很多開源産品中,并沒有直接使用關系資料庫的關系查詢、關系删除等功能,而是直接在代碼中對多個表的查詢結果進行組合。

這兩種方式的優缺點是什麼呢?為什麼很多項目都選擇後者呢?在一個中型以上的項目實踐中,我該選擇哪種方式,或是兩種方式結合使用?

我想:

1,資料表與資料表之間有關聯(Relationship)是肯定的,但是不一定要用外鍵(Foreign Key),為什麼?外鍵本質是一種限制(Constraint),該限制決定了你在增删改查的時候都會有額外開銷。【實際上資料庫在處理外鍵的時候估計也是建立一個中間表根據中間表來做關聯操作,完成後再删除】

2,“對于 “N對N” 的關系,兩個 Model 之間肯定是需要一張中間表的,比如 Student、Class 之間選課關系,是多對多的,肯定需要一張 Enroll 的表來維持,記錄兩個表的主鍵(Primary Key),但是不需要在資料庫層加外鍵限制,隻需要加兩個索引,或作為聯合主鍵。

3,至于查詢,盡量不用 JOIN。但是問題是我确确實實是需要知道多個表的資訊。

比如我要知道某門課(Class,已知 ID)的資訊,同時還有選上該課(Enrolled)的學生資訊(Student)。

使用 JOIN ?沒問題,我相信你可以寫出一個很長的 JOIN 語句。

但是,可能有的地方大概這樣實作的(僞代碼):

getClassInfo(@class_id)

{ SELECT class_col1, class_col2 FROM class WHERE class.id = @class_id }

getStudentInfo(@class_id)

{ SELECT student_col1, student_col2 FROM student WHERE student.id IN (SELECT enroll.student_id FROM enroll WHERE enroll.class_id = @class_id) }

兩種方案各有優缺。

後者最大的一個優點是靈活,比如我們引入緩存(Caching)。

一般來說,一個學校 class 數量不多,并且經常被查詢,系統可能會引入緩存層(如 memcached、redis)來存放 class 對象。

那麼上面的 getClassInfo 其實會變為

{

  if(memcached.has(@class_id) != null)

  {

      return memcached.get(@class_id);

  }

  //查詢資料庫(隻有 class 表),和上面的 SQL 一樣

  memcached.set(@class_id, class_object);

  return class_object;

}