數據庫學習篇三
外鍵的理解
當我們用主鍵唯一標識記錄時,我們就可以在students表中確定任意一個學生的記錄:
id name other columns...
1 小明 ...
2 小紅 ...
我們還可以在classes表中確定任意一個班級記錄:
id name other columns...
1 一班 ...
2 二班 ...
但是我們如何確定students表的一條記錄,例如,id=1的小明,屬於哪個班級呢?由於一個班級可以有多個學生,在關係模型中,這兩個表的關係可以稱爲“一對多”,即一個classes的記錄可以對應多個students表的記錄。
爲了表達這種一對多的關係,我們需要在students表中加入一列class_id,讓它的值與classes表的某條記錄相對應:
id class_id name other columns...
1 1 小明 ...
2 1 小紅 ...
5 2 小白 ...
這樣,我們就可以根據class_id這個列直接定位出一個students表的記錄應該對應到classes的哪條記錄。例如:
小明的class_id是1,因此,對應的classes表的記錄是id=1的一班;
小紅的class_id是1,因此,對應的classes表的記錄是id=1的一班;
小白的class_id是2,因此,對應的classes表的記錄是id=2的二班。
在students表中,通過class_id的字段,可以把數據與另一張表關聯起來,這種列稱爲外鍵。
外鍵並不是通過列名實現的,而是通過定義外鍵約束實現的:
ALTER TABLE students
ADD CONSTRAINT fk_class_id
FOREIGN KEY (class_id)
REFERENCES classes (id);
其中,外鍵約束的名稱fk_class_id
可以任意,FOREIGN KEY (class_id)
指定了class_id
作爲外鍵,REFERENCES classes (id)
指定了這個外鍵將關聯到classes表的id列(即classes表的主鍵)。
通過定義外鍵約束,關係數據庫可以保證無法插入無效的數據。即如果classes表不存在id=99的記錄,students表就無法插入class_id=99的記錄。
由於外鍵約束會降低數據庫的性能,大部分互聯網應用程序爲了追求速度,並不設置外鍵約束,而是僅靠應用程序自身來保證邏輯的正確性。這種情況下,class_id僅僅是一個普通的列,只是它起到了外鍵的作用而已。
要刪除一個外鍵約束,也是通過ALTER TABLE實現的:
ALTER TABLE students
DROP FOREIGN KEY fk_class_id;
注意:刪除外鍵約束並沒有刪除外鍵這一列。刪除列是通過DROP COLUMN ...
實現的。
多對多與一對一關係的理解
多對多關係:
通過一個表的外鍵關聯到另一個表,我們可以定義出一對多關係。有些時候,還需要定義**“多對多”**關係。例如,一個老師可以對應多個班級,一個班級也可以對應多個老師,因此,班級表和老師表存在多對多關係。
多對多關係實際上是通過兩個一對多關係實現的,即通過一箇中間表,關聯兩個一對多關係,就形成了多對多關係:
teachers表:
id name
1 張老師
2 王老師
3 李老師
4 趙老師
classes表:
id name
1 一班
2 二班
中間表teacher_class關聯兩個一對多關係:
id teacher_id class_id
1 1 1
2 1 2
3 2 1
4 2 2
5 3 1
6 4 2
通過中間表teacher_class可知teachers到classes的關係:
id=1的張老師對應id=1,2的一班和二班;
id=2的王老師對應id=1,2的一班和二班;
id=3的李老師對應id=1的一班;
id=4的趙老師對應id=2的二班。
同理可知classes到teachers的關係:
id=1的一班對應id=1,2,3的張老師、王老師和李老師;
id=2的二班對應id=1,2,4的張老師、王老師和趙老師;
因此,通過中間表,我們就定義了一個“多對多”關係。
一對一關係:
一對一關係是指,一個表的記錄對應到另一個表的唯一一個記錄。
例如,students表的每個學生可以有自己的聯繫方式,如果把聯繫方式存入另一個表contacts,我們就可以得到一個“一對一”關係:
id student_id mobile
1 1 135xxxx6300
2 2 138xxxx2209
3 5 139xxxx8086
既然是一對一關係,那爲啥不給students表增加一個mobile列,這樣就能合二爲一了?
如果業務允許,完全可以把兩個表合爲一個表。但是,有些時候,如果某個學生沒有手機號,那麼,contacts表就不存在對應的記錄。實際上,一對一關係準確地說,是contacts表一對一對應students表。
還有一些應用會把一個大表拆成兩個一對一的表,目的是把經常讀取和不經常讀取的字段分開,以獲得更高的性能。例如,把一個大的用戶表分拆爲用戶基本信息表user_info和用戶詳細信息表user_profiles,大部分時候,只需要查詢user_info表,並不需要查詢user_profiles表,這樣就提高了查詢速度。
索引的理解
在關係數據庫中,如果有上萬甚至上億條記錄,在查找記錄的時候,想要獲得非常快的速度,就需要使用索引。
**索引是關係數據庫中對某一列或多個列的值進行預排序的數據結構。**通過使用索引,可以讓數據庫系統不必掃描整個表,而是直接定位到符合條件的記錄,這樣就大大加快了查詢速度。
例如,對於students表:
id class_id name gender score
1 1 小明 M 90
2 1 小紅 F 95
3 1 小軍 M 88
如果要經常根據score列進行查詢,就可以對score列創建索引:
ALTER TABLE students
ADD INDEX idx_score (score);
使用ADD INDEX idx_score (score)
就創建了一個名稱爲idx_score
,使用列score的索引。索引名稱是任意的,索引如果有多列,可以在括號裏依次寫上,例如:
ALTER TABLE students
ADD INDEX idx_name_score (name, score);
索引的效率取決於索引列的值是否散列,即該列的值如果越互不相同,那麼索引效率越高。反過來,如果記錄的列存在大量相同的值,例如gender列,大約一半的記錄值是M,另一半是F,因此,對該列創建索引就沒有意義。
可以對一張表創建多個索引。索引的優點是提高了查詢效率,缺點是在插入、更新和刪除記錄時,需要同時修改索引,因此,索引越多,插入、更新和刪除記錄的速度就越慢。 對於主鍵,關係數據庫會自動對其創建主鍵索引,使用主鍵索引的效率是最高的,因爲主鍵會保證絕對唯一。
在設計關係數據表的時候,看上去唯一的列,例如身份證號、郵箱地址等,因爲他們具有業務含義,因此不宜作爲主鍵。但是,這些列根據業務要求,又具有唯一性約束:即不能出現兩條記錄存儲了同一個身份證號。這個時候,就可以給該列添加一個唯一索引。例如,我們假設students表的name不能重複:
ALTER TABLE students
ADD UNIQUE INDEX uni_name (name);
通過UNIQUE
關鍵字我們就添加了一個唯一索引。也可以只對某一列添加一個唯一約束而不創建唯一索引:
ALTER TABLE students
ADD CONSTRAINT uni_name UNIQUE (name);
這種情況下,name列沒有索引,但仍然具有唯一性保證。其實無論是否創建索引,對於用戶和應用程序來說,使用關係數據庫不會有任何區別。這裏的意思是說,當我們在數據庫中查詢時,如果有相應的索引可用,數據庫系統就會自動使用索引來提高查詢效率,如果沒有索引,查詢也能正常執行,只是速度會變慢。因此,索引可以在使用數據庫的過程中逐步優化。
總結
關係數據庫通過外鍵可以實現一對多、多對多和一對一的關係,外鍵既可以通過數據庫來約束,也可以不設置約束,僅依靠應用程序的邏輯來保證。同時通過對數據庫表創建索引,可以提高查詢速度,通過創建唯一索引,可以保證某一列的值具有唯一性。