數據庫學習

1、如何設計一個數據庫

首先將其劃分爲兩個部分:

  1. 存儲部分:存儲(類似文件系統);
  2. 程序實例:存儲管理(將數據邏輯關係轉換爲數據存儲關係),緩存機制(優化執行效率),SQL解析,日誌管理(記錄數據庫操作),權限劃分(多用戶管理),容災機制,索引管理(優化查詢效率),鎖管理(是數據庫支持併發操作)

2、索引

MySql存儲數據最終是以文件的形式存儲到硬盤的,一般來說,在程序中使用的時候肯定要先把磁盤中的文件數據讀取到內存中,所以造成程序運行的瓶頸是磁盤的IO

解決方案:

  • 計算機系統的優化:當一次IO時,不光把當前磁盤地址的數據,並且把相鄰的數據也讀取到了內存緩衝區中
  • 用一種穩定的數據結構,將每次查找數據時的磁盤IO次數控制在一個很小的數量級
  1. 爲什麼使用索引:避免全表掃描,提高查詢效率

    沒有索引時,直接去讀表數據存放的磁盤塊,讀到數據緩衝區中再查找需要的數據

    有索引時,先讀入索引表,通過索引表直接找到所需數據的物理地址,並把數據讀入數據緩衝區中。

  2. 什麼信息能夠作爲索引:主鍵,唯一鍵(總之就是能夠提供區別信息的字段)

  3. 索引的數據結構

    1. 建立二叉查找樹,進行二分查找,但是在一定情況下可能會退化成一個線性表,從而大大降低查找效率

    2. m階B樹:平衡的m路查找樹

      性質:1.根節點至少包含兩個孩子;2.樹中每個節點最多含有m個孩子(m>=2);3.除根和葉子節點外,其餘節點至少有ceil(m/2)個孩子(ceil爲取上限);4.所有的葉子節點都位於同一層

    3. B+樹:

      特性:1.所有的關鍵字都出現在葉子節點的鏈表中,並且鏈表中的關鍵字是有序的;2.非葉子節點的子樹的指針與關鍵字個數相同;3.非葉子節點僅用來索引,數據都存儲在葉子節點中

      相比較而言,B+樹更適合當做索引的數據結構

      • B樹因爲非葉子節點也存儲數據,所以每個節點都要存儲硬盤指針,B+樹只是用來當做索引,即每個節點可以有更大的度
      • B+樹每一層可以容納的關鍵字個數更多,即一次性讀入內存的需要查找的關鍵字個數越多,相對的磁盤的IO次數就降低了,磁盤讀寫代價降低
      • B+樹爲葉子節點增加了鏈表指針,更容易做範圍查詢,增刪效率也更高
      • B+樹查找路徑是從根到葉子節點,查詢效率穩定
    4. B+樹索引的性能分析:

      • 一般使用磁盤的I/O次數評價索引結構的優劣
      • 預讀:磁盤一般會順序向後讀取一定長度的數據(頁的整數倍)放入內存
      • 局部性原理:當一個數據被用到時,其附近的數據也通常馬上會被使用
      • B+樹的度一般會超過100,因此樹的高度h非常小,一般爲3到5之間,即查找次數少
      • B+樹葉子節點有順序指針,更容易做範圍查詢
  4. 聚簇索引和非聚簇索引

    爲什麼聚簇索引只能有一個:

    ​ 聚簇索引的順序就是數據的物理存儲順序,葉節點就是數據節點。而非聚簇索引的順序與數據物理排列順序無關,葉節點仍是索引節點,只不過有一個指針指向對應的數據塊。而數據的物理存儲順序只能有一個,所以聚簇索引只能有一個

    • InnoDB使用的是聚簇索引,將主鍵組織到一棵B+樹中,而行數據就儲存在葉子節點上,若使用"where id = 14"這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對應的葉節點,之後獲得行數據。若對Name列進行條件搜索,則需要兩個步驟:第一步在輔助索引B+樹中檢索Name,到達其葉子節點獲取對應的主鍵。第二步使用主鍵在主索引B+樹種再執行一次B+樹檢索操作,最終到達葉子節點即可獲取整行數據。

      InnoDB中:

      1. 若一個主鍵被定義,該主鍵則爲聚簇索引;
      2. 若沒有主鍵被定義,則該表的第一個唯一非空索引作爲聚簇索引;
      3. 若不滿足1.2.條件,InnoDB內部會生成一個隱藏主鍵;
      4. 非主鍵索引存儲相關的鍵位和其對應的主鍵值,搜索需要進行兩步
    • MyISAM使用的是非聚簇索引,非聚簇索引的兩棵B+樹看上去沒什麼不同,節點的結構完全一致只是存儲的內容不同而已,主鍵索引B+樹的節點存儲了主鍵,輔助鍵索引B+樹存儲了輔助鍵。表數據存儲在獨立的地方,這兩顆B+樹的葉子節點都使用一個地址指向真正的表數據,對於表數據來說,這兩個鍵沒有任何差別。由於索引樹是獨立的,通過輔助鍵檢索無需訪問主鍵的索引樹。

  5. 索引是建立的越多越好嗎

    1. 數據量小的表不需要建立索引,會額外增加索引開銷
    2. 數據變更需要維護索引,因此更多的索引也就意味着更多的維護成本
    3. 更多的索引需要更多的空間
  6. 聯合索引

    爲什麼使用聯合索引:

    以聯合索引(a,b,c)爲例

    • 減少開銷:相當於建立了 a,ab,abc 三個索引
    • 覆蓋索引:比如:select a,b,c from table where a=xxx and b = xxx and c=xxx,那麼mysql可以直接通過遍歷索引獲取數據,而不用去讀表,從而減少了磁盤IO操作
    • 效率高:索引列越多,通過索引篩選出的數據越少。有1000W條數據的表,有如下sql:select * from table where a = 1 and b =2 and c = 3,假設每個條件可以篩選出10%的數據,如果只有單值索引,那麼通過該索引能篩選出1000W*10%=100w 條數據,然後再回表從100w條數據中找到符合b=2 and c= 3的數據,然後再排序,再分頁;如果是複合索引,通過索引篩選出1000w *10% *10% *10%=1w,然後再排序、分頁,哪個更高效,一眼便知

    聯合索引的最左匹配原則:

    • mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and

      c > 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調整。

    • =和in可以亂序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優化器會幫你優化成索引可以識別的形式

3、鎖模塊

  1. MyISAM和InnoDB關於鎖模塊的區別

    • MyISAM默認使用的是表級鎖,不支持行級鎖

    • InnoDB默認使用的是行級鎖,也支持表級鎖

      InnoDB在使用索引的時候是行級鎖,針對索引加的鎖;未使用索引的時候是表級鎖,因爲要進行全表掃描

  2. 行級鎖

    讀寫鎖(共享鎖/排它鎖),要注意的是MySQL對select操作進行了優化,未加鎖讀,即非阻塞select

  3. 表級鎖

    1. 意向鎖:加意向鎖的目的是爲了表明某個事務正在鎖定一行或者將要鎖定一行。表明加鎖的意圖

      • 意向共享鎖(IS):表明事務意圖在表中的某一行或者某些行上設置共享鎖
      • 意向排它鎖(IX):表明事務意圖在表中的某一行或者某些行上設置排它鎖
    2. 意向鎖在什麼時候使用?

      1. 在一個事務對一張表的某行添加S鎖之前,它必須對該表獲取一個IS鎖

      2. 在一個事務對一張表的某行添加X鎖之前,它必須對該表獲取一個IX鎖

        需要注意的是,意向鎖是InnoDB自動加的,不需要用戶干預

    3. 爲什麼這麼做?

      舉個栗子:

      ​ 當事務A爲表的某一行加了只讀鎖,而不能寫;之後又來一個事務B想要申請整個表的寫鎖,然而如果B申請成功的話,理論上它就能修改表中的任意一行,這與A持有的行鎖是衝突的。而要避免這種衝突,即讓事務B的申請被阻塞,直到A釋放了行鎖。

      數據庫如何判斷這個衝突?

      • 在沒有意向鎖的情況下:

        step1:判斷表是否被其它事務用表鎖鎖住;

        step2:判斷表中的某行或者某些行是否被行鎖鎖住;

        然而在這種情況下,step2是通過遍歷去查詢是否有行鎖,效率可想而知

      • 有意向鎖之後:

        事務A必須先去申請表的意向共享鎖,當申請成功後纔會再去申請某一行或某些行的行鎖

        step1:同上;

        step2:事務B申請表的寫鎖時,發現表上有意向共享鎖,則說明表中已經存在行鎖,因此B的申請就會被阻塞,也不需要去遍歷判斷是否有哪一行有行鎖,效率大大提升

  4. 如何給select設置共享鎖和排它鎖

    • 共享鎖:SELECT … LOCK IN SHARE MODE;
    • 排它鎖:SELECT … FOR UPDATE;
  5. 當前讀VS快照讀

    • 當前讀:加了鎖的crud,讀取到的是數據庫中的最新版本,並保證其它的併發事務不能修改當前記錄

    • 快照讀:不加鎖的非阻塞讀 select,讀到的數據可能不是最新數據

      讀已提交下,兩種結果一致;可重複讀下,兩種結果可能不一致

4、事務

  1. 四大特性:

    • 原子性(Atomicity):指事務包含的所有操作,要麼全部成功提交,要麼全部失敗回滾;

    • 一致性(Consistency):事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態,即事務執行前後都必須處於一致性狀態;

      舉個栗子:轉賬,事務執行之前A和B兩者錢加起來是5000,無論中間經歷怎樣的轉賬,事務結束後,兩者的錢加起來還是5000;

    • 隔離性(Isolation):多個用戶在併發訪問數據庫的時候,每個用戶開啓的事務都不能被其他事務干擾,多個併發事務之間相互隔離;

    • 持久性(Durability):事務一旦被提交,對數據庫的改變就是永久性的;

  2. 併發訪問下出現的問題及隔離級別:

    • 更新丟失:mysql所有事務隔離級別在數據庫層面都可以避免

    • 髒讀:讀取到另一個事務未提交的數據;

      在讀已提交隔離級別及以上均可避免

    • 不可重複讀:在一次事務內,連續讀取幾次數據,出現不一致

      在可重複讀隔離級別及以上均可避免,側重於對同一數據的修改

    • 幻讀:在一次事務內查詢某一範圍結果集,連續兩次查詢結果範圍出現不一致

      在可序列化隔離級別下可以避免,側重於對某一範圍數據的增刪

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