數據庫的三大范式
A:第一范式
??數據庫表中不能出現重復的記錄,每個字段是原子性的不能再分
學生編號 | 學生姓名 | 聯系方式 |
---|---|---|
1001 | 張三 | zs@gmail.com,1359999999 |
1002 | 李四 | ls@gmail.com,13699999999 |
1001 | 王五 | [ww@163.net,13488888888 |
存在問題:
1: 最后一條記錄和第一條重復(不唯一,沒有主鍵)
2: 聯系方式字段可以再分,不是原子性的
B:第二范式
??第二范式是建立在第一范式基礎上的,另外要求所有非主鍵字段完全依賴主鍵,不能產生部分依賴
學生編號 | 學生姓名 | 教師編號 | 教師姓名 |
---|---|---|---|
1001 | 張三 | 001 | 王老師 |
1002 | 李四 | 002 | 趙老師 |
1003 | 王五 | 001 | 王老師 |
1001 | 張三 | 002 | 趙老師 |
確實主鍵:
學生編號(PK) | 學生姓名(PK) | 教師編號 | 教師姓名 |
---|---|---|---|
1001 | 張三 | 001 | 王老師 |
1002 | 李四 | 002 | 趙老師 |
1003 | 王五 | 001 | 王老師 |
1001 | 張三 | 002 | 趙老師 |
以上雖然確定了主鍵,但此表會出現大量的冗余,主要涉及到的冗余字段為“學生姓名”和“教師姓名”,出現冗余的原因在于,學生姓名部分依賴了主鍵的一個字段學生編號,而沒有依賴教師編號,而教師姓名部門依賴了主鍵的一個字段教師編號,這就是第二范式部分依賴。
學生信息表
學生編號(PK) | 學生姓名 |
---|---|
1001 | 張三 |
1002 | 李四 |
1003 | 王五 |
教師信息表
教師編號(PK) | 教師姓名 |
---|---|
001 | 王老師 |
002 | 趙老師 |
教師和學生的關系表
學生編號(PK) fk->學生表的學生編號 | 教師編號(PK) fk->教師表的教師編號 |
---|---|
1001 | 001 |
1002 | 002 |
1003 | 001 |
1001 | 002 |
如果一個表是單一主鍵,那么它就復合第二范式,部分依賴和主鍵有關系
以上是一種典型的“多對多”的設計
C:第三范式
??建立在第二范式基礎上的,非主鍵字段不能傳遞依賴于主鍵字段。(不要產生傳遞依賴)
學生編號(PK) | 學生姓名 | 班級編號 | 班級名稱 |
---|---|---|---|
1001 | 張三 | 01 | 一年一班 |
1002 | 李四 | 02 | 一年二班 |
1003 | 王五 | 03 | 一年三班 |
1004 | 趙六 | 03 | 一年三班 |
從上表可以看出,班級名稱字段存在冗余,因為班級名稱字段沒有直接依賴于主鍵,班級名稱字段依賴于班級編號,班級編號依賴于學生編號,那么這就是傳遞依賴,解決的辦法是將冗余字段單獨拿出來建立表,如:
學生信息表
學生編號(PK) | 學生姓名 | 班級編號 | 班級名稱 |
---|---|---|---|
1001 | 張三 | 01 | 一年一班 |
1002 | 李四 | 02 | 一年二班 |
1003 | 王五 | 03 | 一年三班 |
1004 | 趙六 | 03 | 一年三班 |
班級信息表
班級編號(PK) | 班級名稱 |
---|---|
01 | 一年一班 |
02 | 一年二班 |
03 | 一年三班 |
以上設計是一種典型的一對多的設計,一存儲在一張表中,多存儲在一張表中,在多的那張表中添加外鍵指向一的一方的主鍵
總結:
??第一范式:有主鍵,具有原子性,字段不可分割
??第二范式:完全依賴,沒有部分依賴
??第三范式:沒有傳遞依賴
數據庫設計盡量遵循三范式,但是還是根據實際情況進行取舍,有時可能會拿冗余換速度,最終用目的要滿足客戶需求。
數據庫的存儲引擎
1.查看存儲引擎
- 數據庫中的各表均被(在創建表時)指定的存儲引擎來處理
- 服務器可用的引擎依賴于以下因素:
? MySQL的版本
? 服務器在開發時如何被配置
? 啟動選項
查看當前數據庫有哪些存儲引擎可用,使用mysql> SHOW ENGINES\G
查看支持的數據庫引擎
? 在創建表時,可使用ENGINE選項為CREATE TABLE語句顯式指定存儲引擎。CREATE TABLE TABLENAME (NO INT) ENGINE = MyISAM;
? 如果在創建表時沒有顯式指定存儲引擎,則該表使用當前默認的存儲引擎
? 默認的存儲引擎可在my.ini配置文件中使用default-storage-engine選項指定。
? 現有表的存儲引擎可使用ALTER TABLE語句來改變:ALTER TABLE TABLENAME ENGINE = INNODB;
? 為確定某表所使用的存儲引擎,可以使用SHOW CREATE TABLE或SHOW TABLE STATUS語句:
mysql> SHOW CREATE TABLE tablename\G
mysql> SHOW TABLE STATUS LIKE 'tablename' \G
2.常用的存儲引擎
MyISAM存儲引擎
? MyISAM存儲引擎是MySQL最常用的引擎。
? 它管理的表具有以下特征:
??–使用三個文件表示每個表:
????? 格式文件 — 存儲表結構的定義(mytable.frm)
????? 數據文件 — 存儲表行的內容(mytable.MYD)
????? 索引文件 — 存儲表上索引(mytable.MYI)
??– 靈活的AUTO_INCREMENT字段處理
??– 可被轉換為壓縮、只讀表來節省空間
InnoDB存儲引擎
? InnoDB存儲引擎是MySQL從5.5版本的缺省引擎。
? 它管理的表具有下列主要特征:
??– 每個InnoDB表在數據庫目錄中以.frm格式文件表示
??– InnoDB表空間tablespace被用于存儲表的內容
??– 提供一組用來記錄事務性活動的日志文件
??– 用COMMIT(提交)、SAVEPOINT及ROLLBACK(回滾)支持事務處理
??– 提供全ACID兼容
??– 在MySQL服務器崩潰后提供自動恢復
??– 多版本(MVCC)和行級鎖定
??– 支持外鍵及引用的完整性,包括級聯刪除和更新
MEMORY存儲引擎
? 使用MEMORY存儲引擎的表,其數據存儲在內存中,且行的長度固定,這兩個特點使得MEMORY存儲引擎非常快。
? MEMORY存儲引擎管理的表具有下列特征:
??– 在數據庫目錄內,每個表均以.frm格式的文件表示。
??– 表數據及索引被存儲在內存中。
??– 表級鎖機制。
??– 不能包含TEXT或BLOB字段。
? MEMORY存儲引擎以前被稱為HEAP引擎。
選擇合適的存儲引擎
? MyISAM表最適合于大量的數據讀而少量數據更新的混合操作。MyISAM表的另一種適用情形是使用壓縮的只讀表。
? 如果查詢中包含較多的數據更新操作,應使用InnoDB。其行級鎖機制和多版本的支持為數據讀取和更新的混合操作提供了良好的并發機制。
? 可使用MEMORY存儲引擎來存儲非永久需要的數據,或者是能夠從基于磁盤的表中重新生成的數據。
數據庫的隔離級別
1. 數據庫的四大特性
(1)原子性(Atomicity):原子性是指事務包含的所有操作必須是一個整體,要么全部成功,要么全部失敗。不能事務中某一條或幾條操作的失敗而其他操作影響到數據庫。
(2) 一致性(Consistency):指數據庫只能有一個一致性狀態變為另一個一致性狀態。臥槽,這個用語言怎么說嘛!!!舉個栗子,銀行轉賬A,B兩個用戶一共5000塊錢,那么不管他們怎么轉都只有5000塊錢。
(3) 隔離性(Isolation):指當同時進行多個事務時。一個事務不能被另一個事務的操作干擾。
(4) 持久性(Durability): 指一旦一個事務提交之后,對數據庫的操作是永久的,不能因為其他原因導致丟失所做的操作。
2.問題
(1)由于很多情況是在并發的環境下訪問數據庫,可能會帶來一下幾個問題:
臟讀: 一個事務中讀取到另一個事務未提交的數據。如轉賬是A正在給B賬戶轉錢,而B正好查看賬戶,此時A并未提交事務,就會導致A.B兩看到的賬戶的錢有問題。
不可重復讀:不可重復讀是指在對于數據庫中的某個數據,一個事務范圍內多次查詢卻返回了不同的數據值,這是由于在查詢間隔,被另一個事務修改并提交了。如AB有一個公共賬戶。A 不停的向這個賬戶轉錢,B不停的查看賬戶(有病),會導致B每次看到的錢都不一樣(媽的,加錢還想怎樣)。
虛讀(幻讀): 解釋不來。大概就是A修改了賬戶,B也在修改,A修改在B之后,然而B修改后查看表發現并不是自己修改的數據,就懷疑眼睛花了,就幻覺了。。。。
四種隔離級別
針對這幾種問題,MySQL提供了四種隔離級別來對應:
① Serializable (串行化):可避免臟讀、不可重復讀、幻讀的發生。太慢。基本不用,鎖,只能一個一個來。
② Repeatable read (可重復讀):可避免臟讀、不可重復讀的發生。
③ Read committed (讀已提交):可避免臟讀的發生。
④ Read uncommitted (讀未提交):最低級別,任何情況都無法保證。