mysql底層存儲及IO過程理解


InnoDB維護了一個邏輯空間叫表空間

向上對接開發者,向下對接物理文件

 當創建表時,會自動為表創建一個對應表名的表空間,並在數據庫目錄下生成一個“表名.ibd”的表空間文件。

 

 

存儲結構

物理存儲圖  page頁  extent區   sagement段    書頁,一本書,一套書的關系

最小存儲單元是頁 , 一個頁對應B+樹一個節點

一個區包括多個頁  ,一個段包括多個區

一個page默認大小16kb,區默認大小1M

 

1.innodb中io操作的最小單位。

2.每個頁都有一個對應的從0開始的編號,這個編號叫做頁號。因為表空間的數據文件會被划分成大小相等的頁,所以知道頁號,再根據文件的初始位置,就可以計算出頁在磁盤中的准確地址。

3.一張表對應一個聚集索引,而聚集索引元數據中指定了root page的頁號,因此Innodb引擎可以根據頁號和頁大小計算出索引B+樹root page的准確地址,從而對整個表數據進行操作。

4.段、區都是為了管理空間的存儲狀態,為頁分配空間服務,真正的查詢只需要通過Page No和B+樹中各級節點的關聯關系就可以操作整個表物理空間上的數據。

 

 

從B+樹索引來看

1.一個表的聚簇索引分為兩個段,包含數據的葉子節點的數據段,不包含數據的節點的索引段

2.索引段的page存的是key+指針,數據段的page存的是數據行

3.一個page默認16k,一個索引段的page大約能存1170個索引指針(一個索引指針key占8字節,指針占6字節),

那么根節點就能保存1170*n個指針 (n為根節點的page數)

指向下一層1170*1170*n*m個節點 (m為每個節點平均page數)

指向下一層1170*1170*n*m*k個 葉子節點 (k為每個葉子節點平均page數)

每行數據如果占1k,那么每個葉子節點的page大約能存16條數據,一共就能存1170*1170*n*m*k*16條數據

所以 理論上三層高的B+樹索引能存放超過幾千萬條數據

 

 

B+樹索引磁盤IO次數

1.數據量小的話,直接把索引放到內存中,內存的O(logn)消耗是遠遠低於磁盤io的,所以可以忽略不計

2.對於普通二叉樹,第一個步驟是二分,每次判斷都是一次半數的數量級檢索。假如有100W的數據,大概的時間復雜度是:log2N=1000000N=20的節點獲取,也就是磁盤I/O復雜度最大為O(20),二分的時間復雜度是O(log2N)

3.一個4Kb的磁盤塊將大致可以容納250個下級指針,100萬行目標記錄(假設葉子節點也是只保存了id值,則一個非葉子節點下面也包括大概250個葉子節點)只需log250N=1000000N=3的I/O次數,

充分提升了每次節點I/O帶來的檢索效用,時間復雜度是O(lognN),這里的n是非葉子結點的個數。

(實際上innodb的數據頁大小是16kb,這個n會更大,那么對應的,io次數也會更少)

4.MySQLInnoDB存儲引擎在設計時是將根節點常駐內存的,也就是說查找某一鍵值的行記錄時最多只需要1~3次磁盤I/O操作

 

 

為什么不要把主鍵設置為uuid?

插入效率低啊,為啥呢?

InnoDB默認使用主鍵建立聚簇索引,這種索引必須有邏輯順序的啊,你用UUID這種無序的,每次新增數據是不是要按順序找到相應的位置插入? (如果一個表沒有申明主鍵和一個不為null的唯一索引,InnoDB將會自動增加一個6字節(48位)的整數列,被叫做行ID,聚集數據都是依靠這列的。這列既不能通過任何查詢獲取到也不能做像基於行復制的任何內部操作。)

新插入一行很可能底層page節點,索引節點都會插入一條。人都排好序了 你往中間插,那人家可能一個page16k都占滿了,就為了你還得重新申請頁 頁擴容 分裂,

就像數組中間插值擴容一樣,那效率能不低嗎?

 So  一般主鍵直接用自增的,方便排序 順序插入,如果沒設置主鍵 InnoDB默認用row id 來當主鍵索引,可別自己整個uuid當索引啊


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM