MySQL 執行原理【表】

sayhe110發表於2019-09-09

文章根據《MySQL技術內幕:InnoDB儲存引擎(第二版)》、掘金小冊《MySQL是怎樣執行的:從根兒上理解MySQL》 兩本書得到的總結

文章圖片均截圖自《MySQL技術內幕:InnoDB儲存引擎(第二版)》

本篇文章將介紹MySQL表的邏輯儲存及實現,也就是資料在表中如果組織和存放的。

表的概述

表就是關於特定實體的資料集合,這也是關聯式資料庫模型的核心。

索引組織表

在innodb儲存引擎中,表都是根據主鍵順序組織存放的,這種儲存方式的表稱為索引組織表。

每張表都有主鍵,若沒有則會按如下方式選擇或建立主鍵:

  • 首先判斷表中是否有非空的唯一索引(unique not null)如果有,則該列即為主鍵
  • 如果不符合上述條件,innodb儲存引擎自動建立一個6位元組的指標
  • 當表中有多個非空唯一索引時,innodb儲存引擎將選擇建表時第一個定義的非空唯一索引為主鍵

InnoDB儲存邏輯結構

所有資料都邏輯地存放在一個空間內,這個空間就是我們所說的表空間,表空間可以看做成InnoDB儲存引擎邏輯結構的最高層,結構圖如下(表截圖自《MySQL技術內幕:InnoDB儲存引擎(第二版)》)

1240

從結構圖中,可以看到表空間由段、區、頁、行四大部分組成

  • 段:表空間由各個段組成,常見的段有資料段、索引段、回滾段等
  • 區:段由各個區組成,區由連續頁組成,在任何情況下區的大小都為 1MB
    • 為了保證區中頁的連續性,InnoDB儲存引擎一次從磁碟申請 4~5個區,預設情況下InnoDB儲存引擎頁的大小為16KB,即一個區中一個有64個連續的頁
  • 頁:InnoDB儲存引擎磁碟管理最小單位【會單獨寫篇文章來詳細介紹資料頁】,常見的頁型別有:資料頁、undo頁、系統頁、事務資料頁、插入緩衝點陣圖頁、插入緩衝空閒頁、未壓縮的二進位制大物件頁、壓縮的二進位制大物件頁
  • 行:InnoDB儲存引擎是面向列的,也就是說資料是按行進行存放的

InnoDB行記錄格式

我們正常都是以行為單位向表中插入資料,這些資料在磁碟上存放的格式被稱為 行格式 或者 記錄格式 ,行記錄格式有多種如: CompactRedundantDynamicCompressed,MySQL5.1開始預設行格式為 Compact
可以通過以下命令來修改行記錄格式

CREATE TABLE 表名 (列的資訊) ROW_FORMAT=行格式名稱

ALTER TABLE 表名 ROW_FORMAT=行格式名稱

Compact行記錄格式的結構圖(表截圖自《MySQL技術內幕:InnoDB儲存引擎(第二版)》)如下:

1240
  • 變長欄位長度列表:Compact行記錄格式的首部是一個非NULL變長欄位長度列表,逆序放置
    • 把所有變長欄位的真實資料佔用的位元組長度都存放至變長欄位長度列表中
    • 若列長度小於255位元組,用1位元組表示,若大於255位元組則用2位元組表示
  • NULL 標誌位:指示該行資料中是否有NULL值,有則1表示
  • 記錄頭資訊:固定佔5個位元組,也就是40個二進位制位,不同位代表不同意思,如圖():


1240
  • Redundant行記錄格式:MySQL5.1版本之前的行記錄格式
  • 行溢位資料【下面會詳細介紹】
  • Compressed和Dynamic行記錄格式
    • Dynamic行記錄格式與Compact行記錄格式相似,區別在於處理行溢位資料時不同
    • Compressed行記錄格式與Dynamic行記錄格式不同的是,Compressed行格式會採用壓縮演算法對頁面進行壓縮,以節省空間

行溢位資料

InnoDB儲存引擎可以將一條記錄中的某些資料儲存在真正的資料頁面之外,一般認為只有BLOB,LOB這種大物件資料型別的儲存會把資料存放在頁面之外,但是這種理解是有一點偏差的,
BLOB也可以不將資料存放在頁面之外,而且即便是VARCHAR型別,依然有可能存放為行溢位資料。

記錄中資料太多產生的溢位

不止是BLOB、LOB這種大物件資料太多會產生溢位,VARCHAR型別同樣會產生溢位。

行溢位的臨界點

在列儲存多少個位元組的資料時會發生行溢位呢?
MySQL規定一個資料頁至少存放兩條資料記錄,我們可以先分析下頁中的空間是如何利用的

  • 每個頁除了存放我們資料記錄之外還需要存放其他資訊,比如 File HeaderPage Header 等等,共需要 132 個位元組空間,其他空間都可以被存放資料記錄
  • 每個記錄需要額外的 27 個位元組資訊,27個位元組資訊包括
    • 2個位元組用於儲存真實資料的長度
    • 1個位元組用於儲存列是否是NULL值
    • 5個位元組大小的頭資訊
    • 6個位元組的row_id列
    • 6個位元組的transaction_id列
    • 7個位元組的roll_pointer列

假設一個列中儲存的資料位元組數為n,設計MySQL的大叔規定如果該列不發生溢位的現象,就需要滿足下邊這個式子:

132 + 2×(27 + n) < 16384

得到 n 為8099,也就是說這個列可以存放8099位元組資訊,若大於則為溢位,這只是一個列的情況下,若多列的時候,這個數值就不能作為參考,所以最終的結論是:你不用關注這個臨界點是什麼,只要知道如果我們一條記錄的某個列中儲存的資料佔用的位元組數非常多時,該列就可能成為溢位列

相關文章