有人會對數據庫有這樣的疑問:
因為大多數的數據庫教程上都是告訴你關系數據庫如何去創建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;
- }