MySQL儲存底層原理

K. Bob發表於2020-10-03

MySQL儲存引擎

InnoDB
  InnoDB 的儲存檔案有兩個,字尾名分別是.frm和.idb,其中.frm是表的定義檔案,而.idb是資料檔案。InnoDB 中存在表鎖和行鎖,不過行鎖是在命中索引的情況下才會起作用。InnoDB 支援事務,且支援四種隔離級別(讀未提交、讀已提交、可重複讀、序列化),預設的為可重複讀。

Myisam
  Myisam 的儲存檔案有三個,字尾名分別是.frm、.MYD、.MYI,其中 .frm是表的定義檔案,.MYD是資料檔案,.MYI是索引檔案。Myisam 只支援表鎖,且不支援事務。Myisam 由於有單獨的索引檔案,在讀取資料方面的效能很高 。InnoDB 和 Myisam 都是用 B+Tree 來儲存資料的。

MySQL 的資料、索引儲存結構

資料儲存的原理(硬碟)
  資訊儲存在硬碟裡,硬碟是由很多的碟片組成,通過碟片表面的磁性物質來儲存資料。碟片表面是凹凸不平的,凸起的地方被磁化,代表數字 1,凹的地方沒有被磁化,代表數字 0,因此硬碟可以通過二進位制的形式來儲存表示文字、圖片等的資訊。硬碟是由碟片、磁頭、碟片主軸、控制電機、磁頭控制器、資料轉換器、介面、快取等幾個部分組成。

資料讀寫的原理
  硬碟在邏輯上被劃分為磁軌、柱面以及扇區。
  作業系統以扇區形式將資訊儲存在硬碟上,每個扇區包括 512 個位元組的資料和一些其他資訊,一個扇區有兩個主要部分:儲存資料地點的識別符號和儲存資料的資料段。識別符號就是扇區頭標,包括組成扇區三維地址的三個數字:盤面號,柱面號,扇區號(塊號)。資料段可分為資料和保護資料的糾錯碼(ECC)。在初始準備期間,計算機用 512 個虛擬資訊位元組(實際資料的存放地)和與這些虛擬資訊位元組相應的 ECC 數字填入這個部分。

訪盤請求完成過程

  1. 確定磁碟地址(柱面號,磁頭號,扇區號),記憶體地址(源 / 目)
      當需要從磁碟讀取資料的時候,系統會將資料的邏輯地址傳遞個磁碟,磁碟的控制電路按照定址邏輯將邏輯地址翻譯成實體地址,即確定要讀的資料在哪個磁軌,哪個扇區。
  2. 為了讀取這個扇區的資料,需要將磁頭放到這個扇區上方
      為了實現這一點首先必須找到柱面,即磁頭需要移動對準相應磁軌,這個過程叫做尋道,所耗費時間叫做尋道時間。然後目標扇區旋轉到磁頭下,即磁碟旋轉將目標扇區旋轉到磁頭下,這個過程耗費的時間叫做旋轉時間。
  3. 即一次訪盤請求(讀 / 寫)完成過程由三個動作組成:
    A. 尋道(時間):磁頭移動定位到指定磁軌
    B. 旋轉延遲(時間):等待指定扇區從磁頭下旋轉經過
    C. 資料傳輸(時間):資料在磁碟與記憶體之間的實際傳輸

磁碟的讀寫原理
  系統將檔案儲存到磁碟上時,按柱面、磁頭、扇區的方式進行,即最先是第 1 磁軌的第一磁頭下的所有扇區,然後是同一柱面的下一個磁頭。一個柱面儲存滿後就推進到下一個柱面,直到把檔案內容全部寫入磁碟。
  系統也以相同的順序讀出資料,讀出資料時通過告訴磁碟控制器要讀出扇區所在柱面號、磁頭號和扇區號(實體地址的三個組成部分)進行。

減少 I/O 的預讀原理
  磁碟往往不是嚴格地按需讀取,而是每次都會預讀,即使只需要一個位元組,磁碟也會從這個位置開始,順序向後讀取一定長度的資料放入記憶體。根據區域性性原理:
1、當一個資料被用到時,其附近的資料一般來說也會被馬上使用
2、程式執行期間所需要的資料通常比較集中
3、由於磁碟順序讀取的效率很高(不需要尋道時間,只需要很少的旋轉時間),因此對於具有區域性性的程式來說,預讀可以提高 I/O 效率

  預讀的長度一般為頁(Page)的整數倍。頁是計算機管理儲存器的邏輯塊,硬體及作業系統往往將主存和磁碟儲存分割為連續的大小相等的塊。每個儲存塊稱為一頁(在許多作業系統中,頁的大小通常為 4k),主存和磁碟以頁為單位交換資料,當程式要讀取的資料不在主存中時,會觸發一個缺頁異常。此時系統會向磁碟發出讀盤資訊,磁碟會找到資料的起始位置並向後連續讀取一頁或幾頁的資料載入記憶體中,然後異常返回,程式繼續執行。

MySQL 的索引
  索引的目的是為了查詢的優化,特別是當資料很龐大的時候,一般的查詢演算法有順序查詢、折半查詢、快速查詢等。但是每種查詢演算法都只能應用於特定的資料結構之上,例如順序查詢依賴於順序結構,折半查詢通過二叉查詢樹或紅黑樹實現二分搜尋。因此在資料之外,資料庫系統還維護著滿足特定查詢演算法的資料結構。這些資料結構以某種方式引用資料,這樣就可以在這些資料結構上實現高階查詢演算法,這種資料結構就是索引。

MySQL 的 B+Tree
  系統從磁碟讀取資料到記憶體時是以磁碟塊(block)為基本單位的,位於同一磁碟塊中的資料會被一次性讀取出來,而不是按需讀取。InnoDB 儲存引擎使用頁作為資料讀取單位,頁是其磁碟管理的最小單位,預設 page 大小是 16k。系統的一個磁碟塊的儲存空間往往沒有這麼大,因此 InnoDB 每次申請磁碟空間時都會是若干地址連續磁碟塊來達到頁的大小 16KB。InnDB 在把磁碟資料讀入到磁碟時會以頁為基本單位,在查詢資料時如果一個頁中的每條資料都能助於定位資料記錄的位置,這將會減少磁碟 I/O 的次數,提高查詢效率。
  MySQL 的 InnoDB 儲存引擎在設計時是將根節點常駐記憶體的,因此力求達到樹的深度不超過 3,也就是說 I/O 不需要超過 3 次。由於記憶體中的關鍵字是一個有序表結構,可以利用二分法查詢提高效率。而 3 次磁碟 I/O 操作是影響整個 B-Tree 查詢效率的決定因素。B-Tree 相對於 AVL縮減了節點個數,使每次磁碟 I/O 取到記憶體的資料都發揮了作用,從而提高了查詢效率。
  B+Tree 是在 B-Tree 基礎上的一種優化,使其更適合實現外儲存索引結構,InnoDB 儲存引擎就是用 B+Tree 實現其索引結構。在 B-Tree 中,每個節點中有 key,也有 data,而每一個頁的儲存空間是有限的,如果 data 資料較大時將會導致每個節點(即一個頁)能儲存的 key 的數量很小。當儲存的資料量很大時同樣會導致 B-Tree 的深度較大,增大查詢時的磁碟 I/O 次數,進而影響查詢效率。在 B+Tree 中,所有資料記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只儲存 key 值資訊,這樣可以大大加大每個節點儲存的 key 值數量,降低 B+Tree 的高度。
  B+Tree 在 B-Tree 的基礎上有兩點變化:資料是存在葉子節點中的;資料節點之間是有指標指向的。通常在 B+Tree 上有兩個頭指標,一個指向根節點,另一個指向關鍵字最小的葉子節點,而且所有葉子節點(即資料節點)之間是一種鏈式環結構。因此可以對 B+Tree 進行兩種查詢運算:一種是對於主鍵的範圍查詢和分頁查詢,另一種是從根節點開始,進行隨機查詢。

Myisam 中的 B+Tree
  Myisam 引擎採用的 B+Tree 結構來作為索引結構。由於 Myisam 中的索引和資料分別存放在不同的檔案,所以在索引樹中的葉子節點中存的資料是該索引對應的資料記錄的地址,由於資料與索引不在一起,所以 Myisam 是非聚簇索引

InnoDB 中的 B+Tree
  InnoDB 是以 ID 為索引的資料儲存。採用 InnoDB 引擎的資料儲存檔案有兩個,一個定義檔案,一個是資料檔案。InnoDB 通過 B+Tree 結構對 ID 建索引,然後在葉子節點中儲存記錄。若建索引的欄位不是主鍵 ID,則對該欄位建索引,然後在葉子節點中儲存的是該記錄的主鍵,然後通過主鍵索引找到對應的記錄。

相關文章