數據庫理論


一. 視圖

1. 視圖的基本概念:
  • 視圖是從一個或幾個基本表(或視圖)中導出的虛擬的表。
  • 視圖看上去非常像數據庫的物理表,對它的操作同任何其它的表一樣。當通過視圖修改數據時,實際上是在改變基表中的數據;相反地,基表數據的改變也會自動反映在由基表產生的視圖中。

2. 視圖的作用:
  • 1、視圖能夠簡化用戶的操作
  • 2、視圖使用戶能以多鍾角度看待同一數據
  • 3、視圖對重構數據庫提供了一定程度的邏輯獨立性
  • 4、視圖能夠對機密數據提供安全保護
  • 5、適當的利用視圖可以更清晰的表達查詢
  • 簡單性。看到的就是需要的。視圖不僅可以簡化用戶對數據的理解,也可以簡化他們的操作。那些被經常使用的查詢可以被定義爲視圖,從而使得用戶不必爲以後的操作每次指定全部的條件。
  • 安全性。通過視圖用戶只能查詢和修改他們所能見到的數據。數據庫中的其它數據則既看不見也取不到。數據庫授權命令可以使每個用戶對數據庫的檢索限制到特定的數據庫對象上,但不能授權到數據庫特定行和特定的列上。通過視圖,用戶可以被限制在數據的不同子集上。
    --- 創建計算機系學生的視圖
    create view_tatal_students
    as select id, name, sex
    from students where sdept = 'CS'
    
3. 視圖和表的區別是什麼?
  • 表直接將數據存儲在磁盤上,視圖是將SQL語句存儲到磁盤上;
  • 視圖是建立在表的基礎上,表存儲數據庫中的數據,而視圖顯示已經在表中的數據的外觀;
  • 視圖本身沒有數據,只保存了SQL語句;
  • 次使用視圖時會去執行SQL語句在它的基表中查詢數據,而表卻是實實在在的保存着數據
  • 刪除視圖,表不受影響,而刪除表,視圖不再起作用。

二. 數據庫事務

1. 什麼是數據庫事務:
  • 數據庫事務是構成單一邏輯工作單元的操作集合,要麼全部執行成功,要麼全部不執行。

2. 數據庫事務的特性:(ACID)
  • ① 原子性:是指事務中的所有操作作爲一個整體像原子一樣不可分割,要麼全部成功,要麼全部失敗。
  • ② 一致性:事務的執行成果必須使數據庫從一個一致性狀態到另一個一致性狀態。一致性狀態是指:Ⅰ. 系統的狀態必須滿足數據的完整性約束(主碼,參照完整性,check 約束等);Ⅱ. 系統的狀態反應數據庫本應描述的現實世界的真實狀態,比如轉賬前後兩個賬戶的金額總和應該保持不變;
  • ③ 隔離性:併發執行的事務不會相互影響,其對數據庫的影響和它們串行執行時一樣。比如多個賬戶同時往一個賬戶轉賬,左後賬戶的結果應該和它們按先後順序轉賬的結果一樣;
  • ④ 持久性:事務一旦提交,其對數據庫的更新就是持久的,任何事務或故障都不會導致數據丟失。

3. 原子性是通過什麼機制實現的:
  • 通過日誌來實現的,比如 MySQL中的 InnoDB引擎使用undo log
  • 在操作任何數據之前,首先將數據被分到一個地方,這個存儲數據備份的地方稱爲undo log ,然後進行數據的修改,如果出現了錯誤或者用於執行了rollback語句,系統可以利用undo log中的備份數據將數據恢復到事務開始前的狀態。
  • undo log是邏輯日誌
  • ①:當delete一條記錄時, undo log中會記錄一條對應的insert記錄;
  • ②:當insert一條記錄時, undo log中會記錄一條對應的delete記錄;
  • ③:當update一條記錄時, undo log中會記錄一條對應的update記錄;

4. 持久性是通過什麼機制實現的:
  • 通過日誌來實現的,比如 MySQL 中的 InnoDB 引擎使用 redo log
  • undo log 相反,redo log記錄的是新數據的備份,在事務提交之前,只要將redo log持久化即可,不需要將數據持久化;
  • 當系統奔潰時,雖然數據沒有持久化,但是redo log已經持久化,系統可以根據redo log中的內容,將所有數據恢復到最新的狀態;

5. 隔離性是通過什麼機制實現的:
  • 通過鎖來實現的,在MySQLInnoDB中,鎖可以分爲兩類,共享鎖排他鎖
  • ① 共享鎖:共享鎖將數據變爲只讀形式,不能進行更新,所以也稱爲讀取鎖定。
  • ② 排他鎖:

6. 一致性是通過什麼機制實現的:
  • ACID中,一致性是事務的根本追求,而某些情況下,比如事務的併發執行或者事務故障或系統奔潰等,會對事務的一致性造成破壞。
  • 數據庫系統通過併發控制技術日誌恢復技術來避免這種情況的發生。
  • 併發控制技術保證了事務的隔離性,使數據庫的一致性不會因併發執行的操作而破壞;
  • 日誌恢復技術包括了事務的原子性,使一致性不會因爲事務故障而被破壞,同時也使已提交的數據庫的修改不會因系統奔潰而丟失,即保證了事務的持久性。
  • 換句話說,事務的一致性是通過原子性,持久性,隔離性來實現的。

7. MySQL 的隔離級別:
  • 事務具有隔離性,理論上來說事務之間的執行不應該相互產生影響,其對數據庫的影響應該和它們串行執行時一樣,然而完全的隔離性會導致系統的併發性很低,降低對資源的利用率,因而實際上對隔離性的要求會有所放寬。
  • SQL標準爲事務定義了不同的隔離級別,從低到高分別是:
    {(Read Uncommitted)(Read Committed)(Repeatable Read)(Serializable) \left\{ \begin{aligned} 讀未提交 (Read\ Uncommitted) \\ 讀已提交 (Read\ Committed) \\ 可重複讀 (Repeatable\ Read) \\ 串行化 (Serializable) \end{aligned} \right.
  • 髒讀/不可重複讀/幻讀的概念:
  • ①:髒讀:對於兩個事務T1T2T1讀取了已經被T2更新但是還沒有提交的字段之後,若此時T2回滾,T1讀取的內容就是臨時並且無效的。或者簡單來說,髒讀就是指一個線程中的事務讀取到了另外一個線程中未提交的數據。
  • ②:不可重複讀:不可重複讀: 對於兩個事務T1T2T1讀取了一個字段,然後T2更新了該字段並提交之後,T1再次提取同一個字段,值便不相等了。
  • ③:幻讀:對於兩個事務T1T2T1從表中讀取數據,然後T2進行了INSERT操作並提交,當T1再次讀取的時候,結果不一致的情況發生。
  • 不同的隔離級別可能導致不同的併發異常,如下表:
事務的隔離級別 髒讀 不可重複讀 幻讀
讀未提交 可能 可能 可能
讀已提交 不可能 可能 可能
可重複讀 不可能 不可能 可能
串行化 不可能 不可能 不可能
  • 其中,MySQL默認的隔離級別是可重複讀

  • 級別越高,數據越安全,但性能越低

  • 創建事務的MySQL語法:

  • ①:隱式事務:事務沒有明顯的開啓或者結束的標誌,MySQL中,默認是開啓自動提交的,可以通過以下語句查看:

    select @@autocommit;
    

    select @@autocommit

  • autocommit = 1的情況下,針對SELECT、UPDATE、DELETE、INSERTDQLDML語句的執行,MySQL會自動提交該事務,如果關閉就需要手動提交或者回滾來完成操作。

  • ②:顯式事務:與隱式事務想反,有明顯的開啓或結束標誌。可以通過以下語句來設置:

    set autocommit = 0;
    

    set autocommit = 0;

  • autocommit = 0的情況下,在事務未結束之前,操作是有效的且更改了數據實體,那麼如果有多個事務參與, 肯定會出現各種各樣的數據不一致的情況,這就類似多個線程在沒有鎖的情況下修改同一個全局變量

  • Serializable級別就類似加鎖的方式,同一時刻支持多個事務併發,但是針對DML(Update\Insert\Delete)操作時,當前發起操作的事務會被阻塞,直到其他事務Commit或者Rollback纔會繼續執行事務語句。可見效率十分低下。


三. 索引

1. 索引的概念:
  • 索引是幫助MySQL高效獲取數據的排好序的數據結構。
  • 索引底層的數據結構常見的有以下幾種:二叉樹,紅黑樹,Hash 表,B-Tree;
  • 常見的MySQL主要有兩種結構:Hash索引B+ Tree索引,我們使用的是InnoDB引擎,默認的是B+樹

2. B+Tree索引和Hash索引區別?
  • 哈希索引適合等值查詢,但是無法進行範圍查詢
    +哈希索引沒辦法利用索引完成排序
    哈希索引不支持多列聯合索引的最左匹配規則
    如果有大量重複鍵值的情況下,哈希索引的效率會很低,因爲存在哈希碰撞問題

3. MyISAM 存儲引擎實現:
  • ①:實現結構:B+ 樹;
  • ②:B+ 樹的葉子節點是<key, value>形式,其中,key是索引,value是索引所在那一行的磁盤文件地址。
  • ③:索引文件和數據文件分開存儲,即MyISAM是非聚集索引,有xxx.frm文件,xxx.MYD文件,xxx.MYI文件。
  • InnoDB的數據文件本身就是索引文件。MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。而在InnoDB中,表數據文件本身就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,因此InnoDB表數據文件本身就是主索引。葉節點包含了完整的數據記錄。這種索引叫做聚集索引。因爲InnoDB的數據文件本身要按主鍵聚集,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,則MySQL系統會自動選擇一個可以唯一標識數據記錄的列作爲主鍵,如果不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段作爲主鍵,這個字段長度爲6個字節,類型爲長整形。第二個與MyISAM索引的不同是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的所有輔助索引都引用主鍵作爲data域。
4. InnoDB 存儲引擎實現:
  • ①:表數據文件本身就是按B+ 樹組織的一個索引結構文件,xxx.IBD文件;
  • ②:聚集索引葉節點,包含了完整的數據記錄;
  • ③:這也就是爲什麼InnoDB必須要有主鍵,且推薦使用自增的整型主鍵。

5. 爲什麼 InnoDB 必須要有主鍵?並且推薦用整型的自增主鍵?
  • 因爲InnoDB本身的文件組織形式就是按照B+ 樹組織的一個索引結構文件,所以必須需要一個主鍵纔可以組織起來,如果用戶使用InnoDB存儲引擎建立表的時候,沒有指定主鍵,則MySQL會自動的幫你找到一個合適的唯一索引作爲主鍵,若找不到符合條件唯一索引條件的字段時,會生成類似於ROW_ID的虛擬列充當該InnoDB表的主鍵;
  • 整型的存儲比字段類型要小,而且應爲是InnoDB存儲引擎使用的是B+Tree數據結構,在進行查詢數據是需要對每個元素進行比較,而整型的對比效率是高於其他數據結構的,字符串等。
  • InnoDB使用聚集索引,數據記錄本身被存於主索引(一顆B+Tree)的葉子節點上。這就要求同一個葉子節點內(大小爲一個內存頁或磁盤頁)的各條數據記錄按主鍵順序存放,因此每當有一條新的記錄插入時,MySQL會根據其主鍵將其插入適當的節點和位置,如果頁面達到裝載因子(InnoDB默認爲15/16),則開闢一個新的頁(節點)。
  • 如果表使用自增主鍵,那麼每次插入新的記錄,記錄就會順序添加到當前索引節點的後續位置,當一頁寫滿,就會自動開闢一個新的頁。這樣就會形成一個緊湊的索引結構,近似順序填滿。由於每次插入時也不需要移動已有數據,因此效率很高,也不會增加很多開銷在維護索引上。

4. 索引的設計原則?

5. 什麼情況下索引會失效?
  • ①:如果條件中有or,即使其中有條件帶索引也不會使用 (這也是爲什麼儘量少用or的原因);要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引;

四. 數據庫引擎

  • 數據庫三大引擎:InnoDB、MyISAM、MEMORY

五. 鎖

1. 概念:
  • 鎖是計算機協調多個進程或線程併發訪問某一資源的機制。
  • MySQL的鎖機制比較簡單,不同的搜索引擎支持不同的鎖機制。
  • 比如MyISAM支持表級鎖;
  • InnoDB既支持表級鎖,又支持行級鎖,但默認情況下使用行級鎖。

2. 表級鎖和行級鎖的概念:
  • 表級鎖:開銷小,加鎖快,不會出現死鎖,發生鎖衝突的概率最高,併發度最低;
  • 行級鎖:開銷大,加鎖慢,會出現死鎖,鎖粒度最小,發生鎖衝突的概率最低,併發成都也最高。
  • 很難說哪種鎖更好,只能就具體應用的特點來說哪種鎖更合適。
  • 表級鎖更適合於以查詢爲主,只有少量按索引條件更新數據的應用,如·web應用`;
  • 行級鎖更適合有大量按索引條件併發更新少量不同數據,同時又有併發查詢的業務。

3. MyISAM 表級鎖
  • MyISAM的表級鎖有兩種模式:
    {(Table Read Lock)(Table Write Lock) \left\{ \begin{aligned} 表共享讀鎖 (Table\ Read\ Lock) \\ 表獨佔寫鎖 (Table\ Write\ Lock) \end{aligned} \right.
  • 對於MyISAM表的讀鎖,不會阻塞其他用戶對同一表的讀請求,但會阻塞對同一表的寫請求;
  • 對於MyISAM表的寫鎖,則會堵塞其他用戶對同一表的讀和寫操作。
  • MyISAM在執行查詢語句之前,會自動給涉及的所有表加讀鎖;在執行更新操作之前,會自動給涉及的表加寫鎖,這個過程並不需要用戶干預,因此用戶一般不需要使用命令來顯示加鎖。
  • MyISAM的讀操作於寫操作之間,以及寫寫操作之間是串行的。
  • MyISAM默認的鎖調度是寫優先,由於表鎖粒度大,讀寫之間又是串行的,因此,如果更新操作比較多,MyISAM表可能會出現嚴重的表等待。

  • MyISAM的寫操作示例:

  • 當一個線程獲得對一個表的寫鎖之後,只有持有鎖的線程可以對錶進行更新操作,其他線程的讀寫操作都會阻塞,知道鎖釋放爲止。

    --- 寫鎖定
    lock table student write;  
    --- 執行操作
    --- 釋放鎖
    unlock tables;
    

  • MyISAM的讀阻塞寫示例:
  • 一個Session使用lock table table_name read 給表加讀鎖,這個Session可以鎖定表記錄中的記錄,但更新和訪問其他表都會提示錯誤,同時,另一個Session可以查詢該表的記錄,但更新就會出現鎖等待。

4. InnoDB 行級鎖
  • 共享鎖(S):又稱讀鎖,允許一個事務去讀一行,並阻止其他事務獲得相同數據集的排他鎖;
  • 若數據T對數據A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對AS鎖,但不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖前不能對A做任何修改。
  • 排他鎖(X):又稱寫鎖,允許獲得排他鎖的事務更新數據,並阻止其他事務獲取對相同數據集的共享鎖和排他寫鎖。若事務T對數據對象加上X鎖,事務T可以讀取A也可以修改A,但其他事務不能再對數據A加上任何鎖,直到事務T釋放A上的X鎖。
  • MySQLInnoDB引擎默認的修改數據語句Insert, Delete, Update都會自動給涉及到的數據加上排他鎖,select語句默認不會加任何鎖類型。

  • 5. InnoDB 行級鎖的實現方式:
  • InnoDB加鎖是通過給索引上的索引項加鎖來實現的;
  • 這一點於Oracle不同,Oracle是通過在數據塊中對相應數據行加鎖來實現的;
  • InnoDB這種行鎖實現特點意味着:只有通過索引條件檢索數據,InnoDB才使用行級鎖,否則默認使用表級鎖。

六. 存儲過程

1. 什麼是存儲過程?
  • 存儲過程是一個預編譯的SQL語句,優點是允許模塊化的設計,就是說只需創建一次,以後在該程序中就可以調用多次。如果某次操作需要執行多次SQL,使用存儲過程比單純SQL語句執行要快。

2. 存儲過程的優缺點?
  • 優點:
    ①:存儲過程是預編譯過的,執行效率高。
    ②:存儲過程的代碼直接存放於數據庫中,通過存儲過程名直接調用,減少網絡通訊。
    ③:安全性高,執行存儲過程需要有一定權限的用戶。
    ④:存儲過程可以重複使用,可減少數據庫開發人員的工作量。
  • 缺點:移植性差

七. 數據庫範式

1. 第一範式
  • 數據表中的每一列(字段),必須是不可拆分的最小單元,也就是確保每一列的原子性,而不是集合。比如:有一個列是三年一班,則可拆分爲三年一班

2. 第二範式
  • 數據庫表中不存在非關鍵字段對任一候選關鍵字段的部分函數依賴,也即實體的每個非主鍵屬性完全函數依賴於主鍵屬性。
  • 部分依賴:當主鍵由兩個或兩個以上字段構成,而表中的某些信息通過主鍵的一個字段就能唯一確定,我們稱這樣的依賴關係爲部分依賴。
  • 學生課程表(學號,姓名,專業,課程號,課程名,成績),該表中一個學生可以選多門課,一門課有多個學生。學號和課程號可以唯一確定一條記錄,因此用學號和課程號做主鍵。
  • 表中的姓名、專業通過主鍵中的學號就能唯一確定,而課程名通過課程號唯一確定,這就是部分依賴,這樣的設計不符合第二範式。

  • 不符合第二範式會帶來以下問題:
  • ①:數據信息冗餘,比如表中專業被存儲了很多次;
  • ②:增刪改會出現問題,比如準耶名字更改了,要修改很多地方。

3. 第三範式
  • 在滿足第二範式的基礎上,在實體中不存在非主鍵屬性傳遞函數依賴於主鍵屬性。(表中字段[非主鍵]不存在對主鍵的傳遞依賴)。
  • 比如學生宿舍表(學號,姓名,性別,系號,系名,宿舍號,宿舍電話)。
  • 學號–>姓名,性別系號–>決定系名宿舍號–>決定宿舍電話,也有學號–>系名學號–>宿舍電話
  • 在這樣一張表中則存在着傳遞依賴。也就是系名依賴系號,系號依賴學號,那麼間接的系名依賴學號,宿舍號、宿舍電話和學號之間也有同樣的關係。這樣設計表的同樣會帶來數據冗餘,操作異常等問題。
  • 同樣可以用關係分解的分解的方法來消除傳遞依賴,將這張表分成三張表。

4. BCNF 範式

八. 數據庫優化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章