1. 程式人生 > >《mysql技術內幕 InnoDB存儲引擎(第二版)》閱讀筆記

《mysql技術內幕 InnoDB存儲引擎(第二版)》閱讀筆記

大小 根節點 idp size 建立 隔離 緩沖 strong 需要

一、mysql架構

mysql是一個單進程多線程架構的數據庫。

二、存儲引擎

InnoDB:

  • 支持事務
  • 行鎖
  • 讀操作無鎖
  • 4種隔離級別,默認為repeatable
  • 自適應hash索引
  • 每張表的存儲都是按主鍵的順序記性存放
  • 支持全文索引(InnoDB1.2.x - mysql5.6)
  • 支持MVCC(多版本並發控制)實現高並發

MyISAM:

  • 不支持事務
  • 表鎖
  • 支持全文索引

三、InnoDB體系架構

技術分享

1、後臺線程

  • Master Thread
    • 負責將緩沖池中的數據異步刷新到磁盤,保證數據的一致性
  • IO Thread
    • 負責IO請求的回調處理  
  • Purge Thread
    • 回收已經使用並分配的undo頁(事務提交後,其所使用的undolog不再需要)

2、內存池

  • 緩沖池(一塊內存區域)
    • InnoDB基於磁盤存儲,將記錄按照的方式進行管理(由於基於磁盤,速度較慢,所以需要引入緩沖池提高性能)
    • 讀取頁:先從緩沖池獲取,緩沖池沒有,才會從磁盤獲取
    • 修改頁:先寫重做日誌緩沖,再修改緩沖池中的頁,然後以一定的頻率刷新到磁盤(Checkpoint機制),在還沒有刷新到磁盤之前,該頁被稱為臟頁
    • innodb_buffer_pool_size設置大小
    • 存放對象:索引頁、數據頁、自適應hash索引和lock信息
    • 緩沖池可以配置多個(innodb_buffer_pool_instances),每個頁根據hash值平均分配到不同的緩沖池實例中,用於減少數據庫內部資源競爭
  • LRU List
    • 將最新的頁放在隊列前端,最近最少使用的放在尾端,當緩沖池不夠用時,將尾端的頁刪除出緩沖池(如果此頁是臟頁,會先刷新到磁盤)。innodb采用的是midpoint技術進行LRU,具體參看《MySQL技術內幕 InnoDB存儲引擎》
  • Flush List
    • 臟頁列表
  • 重做日誌redolog緩沖
    • 為了防止臟頁在刷新到磁盤時宕機,必須先redolog,再修改頁;
    • 數據庫發生宕機時,通過redolog完成數據的恢復(ACID-D持久性
    • 默認大小8M,通過innodb_log_buffer_size
    • 將redolog緩沖刷新到redolog文件中的時機
      • master會將redolog緩沖每隔1s刷新到redolog文件中
      • 每個事物提交
      • redolog緩沖池剩余空間小於1/2
  • Checkpoint
    • 緩沖池不夠用時,將臟頁刷新到磁盤
    • 數據庫宕機時,只需要重做Checkpoint之後的日誌,縮短數據庫的恢復時間
    • redolog不可用時,將臟頁刷新到磁盤

四、InnoDB邏輯存儲結構

技術分享

1、表空間

  • 默認情況下,只有一個表空間ibdata1,所有數據存放在這個空間內
  • 如果啟用了innodb_file_per_table,則每張表內的數據可以單獨放到一個表空間內
    • 每個表空間只存放數據、索引和InsertBuffer Bitmap頁,其他數據還在ibdata1中

2、Segment段(InnoDB引擎自己控制)

  • 數據段:B+ tree的葉子節點
  • 索引段:B+ tree的非葉子節點
  • 回滾段

3、Extent區

  • 每個區的大小為1M,頁大小為16KB,即一個區一共有64個連續的頁(區的大小不可調節,頁可以)

4、Page頁

  • InnoDB磁盤管理的最小單位
  • 默認每個頁大小為16KB,可以通過innodb_page_size來設置(4/8/16K)
  • 每個頁最多存放7992行數據

5、Row行

五、索引

1、hash索引

  • 定位數據只需要一次查找,O(1)
  • 自適應hash索引:InnoDB會監控對表上各個索引頁的查詢,如果觀察到建立hash索引可以帶來速度提升,則建立hash索引(即InnoDB會自動的根據訪問頻率和模式來自動的為某些熱點頁建立hash索引)
  • 默認是開啟的
  • 只可用於等值查詢,不可用於範圍查詢

2、B+樹索引

  • 樹的高度一般為2~4層,需要2~4次查詢(100w和1000w行數據,如果B+ tree都是3層,那麽查詢效率是一樣的)
  • B+樹索引能查到的是數據行所在的頁
  • 包含聚集索引和輔助索引

3、聚集索引

  • 即主鍵索引
  • 葉子節點存放的是行記錄數據所在的頁,而頁中的每一行都是完整的行(葉子節點也被稱為數據頁)
  • 針對範圍查詢也比較快

聚集索引圖:

其中,根節點部分的Key:80000001代表主鍵為1;Pointer:0004代表指向數據頁的頁號(即第4頁);

數據頁節點的的PageOffset:0004代表第4頁,其中存儲的數據是完整的每一行。

技術分享

4、輔助索引

  • 葉子節點存放的也是行記錄數據所在的頁,但還是頁中存放的不是完整的行,而是僅僅是一對key-value和一個指針,該指針指向相應行數據的聚集索引的主鍵
  • 假設輔助索引樹高3層,聚集索引樹為3層,那麽根據輔助索引查找數據,需要先經過3次IO找到主鍵,再經過3次IO找到行做在的數據頁
  • 針對輔助索引的插入和更新操作:輔助索引頁如果在緩沖池中,則插入;若不在,則點放到InsertBuffer對象中,之後在以一定的平率進行InsertBuffer和輔助索引頁子節點的合並

輔助索引圖:

其中,idx_c表示對第c列做了索引;idx_c中的Key:7fffffff代表c列的一個值,其實是-1;idx_c中的Pointer:80000001代表該行的主鍵是80000001,即1;下面的就是聚集索引部分。

技術分享

5、聯合索引(多列索引)

  • 左邊匹配原則(如果索引為(a,b),則where a=x可以用到索引,但是b=x用不到,如果是覆蓋索引有可能會用到)

6、覆蓋索引

  • 從輔助索引中直接獲取記錄
  • 對於統計操作,例如count(1),有可能聯合索引,右邊也會匹配(優化器自己會做),因為count(1)操作不需要獲取整行的詳細數據,所以不需要去聚集索引的葉子節點去獲取數據,直接在輔助索引樹中就完成了操作
  • select username from xxx where username=‘lisi‘,如果username是輔助索引,那麽整個查詢在輔助索引樹上就可以完成,因為輔助索引樹上雖然沒有保存完整的行,但是保存著<username,lisi>這個key-value對;如果select username, age from xxx where username=‘lisi‘,那麽就要走聚集索引了

六、鎖

1、latch

  • 保證並發線程操作臨界資源的正確性
  • 自旋鎖,自旋指定的次數後,若還沒獲取到鎖,則進入等待狀態,等待被喚醒

2、lock

  • 事務鎖,鎖定的可能是表、頁或行
  • 釋放點:事務commit或rollback
  • 兩種標準的行級鎖
    • 共享鎖:S lock,事務T1獲取了r行的S鎖,事務T2也可以獲取r行的S鎖
    • 排他鎖:X lock,事務T1獲取了r行的S鎖,事務T2就不能獲取r行的X鎖;事務T1獲取了r行的X鎖,事務T2就不能獲取r行的X/S鎖

七、事務

1、隔離級別

  • 讀不提交
  • 讀並且提交
    • 可避免臟讀:一個事務讀到另一個事務沒有提交的數據,如果另一個事務發生回滾,第一個事務讀到的數據就是垃圾數據
  • 可重復讀
    • 會有幻讀,InnoDB通過Next-Key Lock解決了
      • 幻讀:指兩次執行同一條 select 語句會出現不同的結果,第二次讀會增加一數據行,並沒有說這兩次執行是在同一個事務中。使用表鎖即可避免。
    • 可避免不可重復讀:在同一個事務中兩條一模一樣的 select 語句的執行結果的比較。如果前後執行的結果一樣,則是可重復讀;如果前後的結果可以不一樣,則是不可重復讀。通常是發生了update。增加讀取時的共享鎖(禁止修改)即可避免。
    • 默認的事務隔離級別
  • 序列化

《mysql技術內幕 InnoDB存儲引擎(第二版)》閱讀筆記