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

1、mysql架構html

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

 

2、存儲引擎mysql

InnoDB:sql

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

MyISAM:數據庫

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

 

3、InnoDB體系架構多線程

一、後臺線程架構

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

二、內存池併發

  • 緩衝池(一塊內存區域)
    • 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不可用時,將髒頁刷新到磁盤

 

4、InnoDB邏輯存儲結構異步

一、表空間高併發

  • 默認狀況下,只有一個表空間ibdata1,全部數據存放在這個空間內
  • 若是啓用了innodb_file_per_table,則每張表內的數據能夠單獨放到一個表空間內
    • 每一個表空間只存放數據、索引和InsertBuffer Bitmap頁,其餘數據還在ibdata1中

二、Segment段(InnoDB引擎本身控制)

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

三、Extent區

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

四、Page頁

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

五、Row行

 

5、索引

一、hash索引

  • 定位數據只須要一次查找,O(1)
  • 自適應hash索引:InnoDB會監控對錶上各個索引頁的查詢,若是觀察到創建hash索引能夠帶來速度提高,則創建hash索引(即InnoDB會自動的根據訪問頻率和模式來自動的爲某些熱點頁創建hash索引)
  • 默認是開啓的
  • 只可用於等值查詢,不可用於範圍查詢

二、B+樹索引

  • 樹的高度通常爲2~4層,須要2~4次查詢(100w和1000w行數據,若是B+ tree都是3層,那麼查詢效率是同樣的)
  • B+樹索引能查到的是數據行所在的頁
  • 包含彙集索引和輔助索引

三、彙集索引

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

彙集索引圖:

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

數據頁節點的的PageOffset:0004表明第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;下面的就是彙集索引部分。

 

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

  • 左邊匹配原則(若是索引爲(a,b),則where a=x能夠用到索引,可是b=x用不到,若是是覆蓋索引有可能會用到)

六、覆蓋索引

  • 從輔助索引中直接獲取記錄
  • 對於統計操做,例如count(1),有可能聯合索引,右邊也會匹配(優化器本身會作),由於count(1)操做不須要獲取整行的詳細數據,因此不須要去彙集索引的葉子節點去獲取數據,直接在輔助索引樹中就完成了操做
  • select username from xxx where username='lisi',若是username是輔助索引,那麼整個查詢在輔助索引樹上就能夠完成,由於輔助索引樹上雖然沒有保存完整的行,可是保存着<username,lisi>這個key-value對;若是select username, age from xxx where username='lisi',那麼就要走彙集索引了

 

6、鎖

一、latch

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

二、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鎖

7、事務

一、隔離級別

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

這裏有美團的一篇文章,很是好:http://tech.meituan.com/mysql-index.html

補充:摘自:https://tech.meituan.com/mysql-index.html

1、B+樹結構:

2、從B+樹查找數據流程

3、B+樹性質

相關文章
相關標籤/搜索