數據庫基礎(數據庫的由來 + 第一、二、三範式)

一、數據庫的產生原理

1.1 無紙化辦公

將數據存在文件中。
在這裏插入圖片描述

1.2 李氏查詢—SQL

所有計算機的問題都可以通過增加一個中間層來解決。

中間層上要有邏輯的數據結構。

學生信息:[學號,姓名,性別,入學日期,班級,地址] 

課程信息:[課程號,課程名,授課老師] 

選課 :[學號,課程號,成績]

小李決定把這些東西稱爲“” ,其中的每一項稱爲“列”/“字段”/“屬性”每一列都有類型,例如字符型,日期型,數字型等等。

查詢的話是用類似這樣進行的: 
SELECT  學號,姓名 
FROM 學生信息 
WHERE  入學日期='1991-9-1'

想把幾個表連接起來查詢也可以:
SELECT 學號,姓名, 課程名,成績
FROM 學生信息 s , 課程信息 c, 選課 sc
ON s.學號=sc.學號 AND c.課程號=sc.課程號 
WHERE   課程名='操作系統'  AND 成績<60 

很明顯小李需要寫一個解析器把這樣的語句變成內部對文件的操作, 還好小李已經有一點編譯原理的基礎了, 努力一下還是能寫出來的。

在這裏插入圖片描述
小李得意的把這套查詢稱爲“李氏查詢” , 李氏查詢用起來簡便快捷, 最大的好處是用戶完全不用考慮物理層的那些文件的結構,只需要關注邏輯層的“”就可以了。—— 其實李氏查詢就是SQL

有了一箇中間的邏輯層,還帶來了一個額外的好處:現在小李可以對物理層的文件存儲進行一些優化。爲了加快訪問速度,小李不再採用簡單的逗號分隔的文件,還增加了索引、緩存、查詢優化等手段。

1.3 併發訪問
  1. 原來單機的軟件紛紛轉爲支持網絡訪問的系統
  2. 不僅僅是重構, 還包含了重要的功能增強:網絡訪問, 從單機軟件變成了**客戶端-服務器結構(C/S)**的軟件。

在這裏插入圖片描述
3. 把基於文件的操作改變成基於行的操作: 每個人的修改隻影響這一行
4. 遇到兩個人對同一行的修改,解決辦法爲:給這一行加鎖, 在劉老師讀取了1000元, 扣除300元,並且把700 寫回到數據庫之前, 不允許金老師操作,這樣就不會亂掉了。

1.4 原子性問題(事務、Undo日誌、操作的冪等性)
  1. 轉賬這個操作,必須得是原子的: 要麼全部發生, 要麼根本不發生
  2. 把類似這樣的操作叫做“事務”
  3. 做真正的操作之前,先把要做的事記錄下來形成日誌(Log),這個日誌中包括修改的數據項標識, 數據項的舊值(修改前的值)和新值(修改後的值), 然後再進行真正的數據庫修改
  4. 剛開始的時候事務處於活動狀態, 只有所有的操作都正確無誤的寫入了磁盤,纔會進入提交狀態, 否則就要回滾修改。

除了原子性之外,事務還有持久性,隔離性,一致性
詳情見:數據庫的事務四大原則-ACID

關於“事務”,用“Undo日誌”的方式來實現它。

比如旺財有200塊錢, 小強有50 塊錢,現在旺財要給小強轉賬,假設轉100塊。怎麼實現要麼不做,要麼全做的?

執行真正的操作之前,要先記錄數據項原來的值。拿轉賬這個例子,把這個事務命名爲T1,在做真正的轉賬之前,一定要在我的日誌文件中記錄下事務開始之前的他倆賬號餘額

[事務T1,  旺財原有餘額 , 200]
[事務T1, 小強原有餘額, 50 ] 

如果事務執行到一半,就斷電了,那數據庫重啓以後我就根據undo的日誌文件來恢復

“嗯,那要是系統恢復的過程中又斷電了,還得再次恢復,那數據豈不變得一團糟? ” CPU阿甘對斷電心有餘悸。

“你們仔細想想,即使我把旺財的餘額和小強的餘額恢復了100次,會有什麼結果?”

“如果每次都試圖把旺財的餘額設爲200, 小強餘額設爲50, 做多少次都沒問題, 因爲他倆原來的餘額就是那麼多 !” Tomcat恍然大悟。

“這就叫做操作的冪等性,知道不? 我可以一直做恢復,恢復過程中斷電也不怕,只要把恢復做完就行。” 老頭兒看到時機一到,立刻上升爲理論。

“恢復數據的時候, 那你怎麼才能知道一個事務沒有完成呢?” Tomcat接着問道。

[開始事務 T1]
[事務T1, 旺財原有餘額,200]
[事務T1, 小強原有餘額,50]
[提交事務 T1]

“Undo日誌文件中不僅僅只有餘額, 事務的開始和結束也會記錄,如果我在日誌文件中看到了[提交事務 T1], 或者 [回滾事務 T1], 我就知道這個事務已經結束,不用再去理會它了, 更不用去恢復。 如果我只看到 [開始事務 T1], 而找不到提交或回滾,那我就得恢復。比如下面這個:

[開始事務 T1]
[事務T1, 旺財原有餘額,200]
[事務T1, 小強原有餘額,50]

“特別是,” 老頭補充道, “ 我恢復以後, 需要在日誌文件中加上一行 [回滾事務 T1] , 這樣下一次恢復我就不用再考慮T1這個事務了。”

“不對吧, 你這個Undo日誌文件會面臨和數據文件一樣的問題, 都是需要加載到內存才能讀寫, 要不然會太慢。 那要是連日誌文件還沒寫好就斷電了,那不還是玩完?” Ngnix 目光如炬,向深層次挖掘。

這是個絕佳的問題,大家紛紛把目光殺向數據庫老頭兒,希望這一次能把他打翻在地。
其實很簡單,只需要遵循兩條簡單的規則就可:

  1. 在你把最新餘額寫入硬盤之前, 一定要先把相關的Undo日誌記錄寫入硬盤。 例如[事務T1, 旺財原有餘額,200] 一定要在旺財的新餘額=100寫入硬盤之前寫入。
  2. [提交事務 T1] 這樣的Undo日誌記錄一定要在所有的新餘額寫入硬盤之後再寫入。
1.5 安全
  1. 添加權限控制
趕緊加上一個權限系統, 小李想了想,  先定義三大類權限:
1. 對數據操作的, 例如SELECT, UPDATE, INSERT等
2. 對結構操作的, 例如創建表,修改表,等
3. 做管理的, 例如備份數據, 創建用戶等
然後就可以把這些權限授予某個用戶了, 很多時候,還需要把表附加上, 像這樣:
GRANT  SELECT on 財務表 to  系主任
GRANT  CREATE_TABLE to 張老師

至此。這個系統的中間層完全可以剝離出來,形成一個完整的軟件了, 小李把它稱爲:數據庫
在這裏插入圖片描述


二、第一範式、第二範式、第三範式

  1. 關係數據庫最忌諱的就是在一個單元格里存儲多個值 —— 不滿足第一範式的數據庫就不是關係數據庫
2.1 第一範式(1NF)

第一範式是指數據庫表中的每一列都是不可分割的基本數據項,強調列的原子性同一列中不能有多個值,即實體中的某個屬性不能有多個值或者不能有重複的屬性。

說明:在任何一個關係數據庫中,第一範式(1NF)是對關係模式的基本要求,不滿足第一範式(1NF)的數據庫就不是關係數據庫。

例如,由“職工號”“姓名”“電話號碼”組成的表(一個人可能有一部辦公電話和一部移動電話),這時將其規範化爲1NF可以將電話號碼分爲“辦公電話”和“移動電話”兩個屬性,即職工(職工號,姓名,辦公電話,移動電話)。

2.2 第二範式(2NF)

第二範式建立在第一範式的基礎上,即滿足第二範式一定滿足第一範式,第二範式要求數據表每一個實例或者行必須被唯一標識。
除滿足第一範式外還有兩個條件,一是表必須有一個主鍵;二是沒有包含在主鍵中的列必須完全依賴於主鍵,而不能只依賴於主鍵的一部分。(所有屬性僅僅依賴於主鍵的情況)

例如,在選課關係表(學號,課程號,成績,學分),關鍵字爲組合關鍵字(學號,課程號),但由於非主屬性學分僅依賴於課程號對關鍵字(學號,課程號)只是部分依賴,而不是完全依賴,因此此種方式會導致數據冗餘以及更新異常等問題。
解決辦法是將其拆分爲兩個關係模式:學生表(學號,課程號,分數)和課程表(課程號,學分),新關係通過學生表中的外關鍵字課程號聯繫,在需要時進行連接。

2.3 第三範式(3NF)

如果關係模型R是第二範式,且每個非主屬性都不傳遞依賴於R的候選鍵,則稱R是第三範式的模式。(沒有傳遞依賴)
在這裏插入圖片描述
上表存在:訂單號能決定用戶ID,而用戶ID 能決定用戶名稱。即,存在傳遞依賴: 訂單號->用戶ID->用戶名稱

此時用戶信息無法單獨管理,所以繼續拆分:
在這裏插入圖片描述
在這裏插入圖片描述
拆分完就沒有傳遞依賴了, 我們可以稱之爲 第三範式 了。
在這裏插入圖片描述

把表不斷地拆分後,把這些“分散表”連接(Join)起來才能形成最初的那張表。如果在數據量特別巨大的時候,這種連接很耗時。所以在實踐中有時候不得不違反範式違反第三範式),做點數據的冗餘


參考文章:

  1. 數據庫-第一範式、第二範式、第三範式、BC範式、第四範式簡析
  2. [數據庫] 第一範式、第二範式、第三範式、BC範式
  3. 《碼農翻身》
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章