MySQL表空間結構詳解表空間到段頁操作
在MySQL架構和存儲引擎專題中介紹了使用不同存儲引擎創(chuàng)建表時生成的表空間數據文件,在本章節(jié)主要介紹使用InnoDB存儲引擎創(chuàng)建表時生成的表空間數據文件
?????一、什么是表空間結構
創(chuàng)建表時生成的數據文件在哪里?
表空間文件是用來存儲表中數據的文件,表空間文件的大小由存儲的數據多少決定,不同的表空間文件存儲數據的種類也有所不同
在MySQL中表空間分為五類,包括: 系統(tǒng)表空間
、獨立表空間
、通用表空間
、臨時表空間
和 撤銷表空間
,這些在上面的InnoDB架構圖中都有體現(xiàn)。
1.1 表空間與表空間文件的關系是什么?
表空間可以理解為MySOL為了管理數據而設計的一種數據結構,主要描述的對結構的定義,表空間文件是對定義的具體實現(xiàn),以文件的形式存在于磁盤上
系統(tǒng)表空間、獨立表空間、通用表空間、臨時表空間和撤銷表空間的作用?
后面我們會詳細介紹每種類型的表空間的作用。
?????二、用戶數據在表空間中是怎么存儲的?
- 首先明確一點,用戶的數據以
數據行
的方式存儲在對應的表空間文件中,那么表空間中很多個數據行就需要進行管理,以便后續(xù)進行高效的查詢; - 為了方便管理,表空間由段(segment)、區(qū)組(group)、區(qū)(extent)、頁(page)、數據行組成其中頁是 InnoDB 磁盤管理的最小單位;
?????三、為什么要使用頁這個數據管理單元?
- 首先要明確一點,MySQL中的
頁
是應用層的一個概念,是MySQL根據自身的應用場景,定義的一種數據結構。 - 通常操作系統(tǒng)中的文件系統(tǒng)在管理磁盤文件時以4KB大小為一個管理單元,稱為"數據塊",但是在數據庫的應用場景里,查詢時數據量都比較大,如果也使用4KB做數據存儲的最小的單元,就顯的有點小了,同時會造成頻繁的磁盤1/0,導致降低效率;
- 所以MySQL根據自身情況定義了
大小為16KB的頁
,做為磁盤管理的最小單位; - 每次內存與磁盤的交互至少讀取一頁,所以在磁盤中每個頁內部的地址都是連續(xù)的,之所以這樣做,是因為在使用數據的過程中,根據局部性原理,將來要使用的數據大概率與當前訪問的數據在空間上是臨近的,所以一次從磁盤中讀取一頁的數據放入內存中,當下次查詢的數據還在這個頁中時就可以從內存中直接讀取,從而減少磁盤I/0,提高性能
MySQL根據自身的應用場景使用頁做為數據管理單元,最主要的目的就是減少磁盤I0,提高性能。
3.1 什么是局部性原理?
局部性原理是指程序在執(zhí)行時呈現(xiàn)出局部性規(guī)律,在一段時間內,整個程序的執(zhí)行僅限于程序中的某一部分。相應地,執(zhí)行所訪問的存儲空間也局限于某個內存區(qū)域,局部性通常有兩種形式:時間局部性和空間局部性。
時間局部性
(TemporalLocality): 如果一個信息項正在被訪問,那么在近期它很可能還會被再次訪問。空間局部性
(SpatialLocality): 將來要用到的信息大概率與正在使用的信息在空間地址上是臨近的。
?????四、數據頁有哪些基本特性是必須要掌握的? - 頁
- 頁的
16KB
的大小是MySQL的一個默認設置,可以適用于大多數場景,當然也可以根據自己的實際業(yè)務場景進行修改頁的大小,通過系統(tǒng)變量 innodb_page_size 進行調整與查看,在調整頁大小的時候需要保證設置的值是操作系統(tǒng)"數據塊"4KB的整數倍,從而保證通過操作系統(tǒng)和磁盤交互時"數據塊"的完整性,不被分割或浪費,所以規(guī)定了 innodb_page_size 可以設置的值,分別是 4096、8192、16384、32768、65536,對應4KB、8KB、16KB、32KB、64KB: - 每一個頁中即使沒有數據也會使用
16KB
的存儲空間,同時與索引的B+樹中的節(jié)點對應,后續(xù)在索引專題中詳細講解B+樹的內容,查看頁的大小,可以通過系統(tǒng)變量innodb_page_size
查看
mysql> SHOW VARIABLES LIKE 'innodb_page_size'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | innodb_page_size | 16384 | # 16KB +------------------+-------+ 1 row in set, 1 warning (0.04 sec)
在不同的使用場景中,頁的結構也有所不同,在MVSOL中有多種不同類型的頁,但不論哪種類型的頁都會包含頁頭
(File Header)和頁尾
(File Trailer),在這頁頭和頁尾之間的頁主體
信息根據不同的類型有不同的結構,最常用的就是用來存儲數據和索引的"索引頁",也叫做"數據頁",頁的主體信息使用數據"行"進行填充,行的結構我們在下面的章節(jié)中進行詳細介紹,頁的基本結構如下圖所示:
?????五、查詢的數據超過一頁的大小,怎么提高查詢效率? - 區(qū)
要解答這個問題,我們先要弄明白前置的幾個小問題,首先通過前面的內容,我們了解到磁盤中每個頁內部的地址都是連續(xù)的,那么我們可以繼續(xù)提問:
1. 不同的頁在磁盤中是不是連續(xù)的?
2. 如果頁不連續(xù)對訪問效率是否有影響?
3. InnoDB如何保證頁在磁盤中的連續(xù)性?
解決以上三個小問題之后當前的問題自然也就解決了,我們接著往下看。
5.1 不同的頁在磁盤中是不是連續(xù)的呢?
- 答案是不一定,在不做任何控制的情況下,不同頁在磁盤中申請的地址
大概率是不連續(xù)
的。 - 我們可以很快的分析出來連續(xù)的地址對查詢效率的影響,如果頁在磁盤中可以被連續(xù)讀取,那么查詢效率就高,否則果詢效率就低。
5.2 為什么不連續(xù)的地址會降低查詢的效率?
- 當存儲介質是機械硬盤時,訪問不連續(xù)的地址會帶來磁盤尋址的開銷,也就是磁頭在不同盤面、磁道和扇區(qū)的機械轉動,這個過程稱為
磁盤隨機訪問
,非常影響效率,磁盤結構如下圖所示:
扇區(qū)是磁盤中存儲數據的最小單位,固定為 512B
經過以上的分析,當查詢的數據大于一頁時不加任何控制會產生磁盤隨機訪問 ,這個是影響查詢效率的主要因素,那么現(xiàn)在怎么提高查詢效率的問題就變成了,頁在磁盤中是否連續(xù)的問題,我們換個問法。
5.3 InnoDB如何保證頁在磁盤中的連續(xù)性?
- 為了解決磁盤隨機訪問非常低效的問題,需要盡可能在磁道上讀取連續(xù)的數據,減少磁頭的移動,從而提升效率,MySQL使用
Extent(區(qū))
這個結構來管理頁,規(guī)定每個區(qū)固定大小為 1MB ,可以存放 64 個頁,這時如果跨頁讀數據時,大概率都在附近的地址,可以大幅減少碰頭移動;
提示: 我們學習的主要是解決問題的思路,大家要搞懂為什么要有區(qū)以及區(qū)解決了什么問題,至于區(qū)的固定大小不用刻意去記,現(xiàn)階段是1MB,以后的版本會不會改變也說不好。同時,如果頻繁的讀取某個區(qū)中的頁,可以把整個區(qū)都讀取出來放入內存中,減少后續(xù)查詢對磁盤的訪問次數,進一步提升效率,如圖所示
通過對問題的分析,我們了解到 InnoDB
中用來組織頁的數據結構–區(qū),并且每個區(qū)固定大小為1MB ,可以包含64個連續(xù)的頁,查詢的數據超過一頁大小時,可能會有以下幾種情況:
頁在區(qū)內是相鄰的
: 磁盤順序I/0,可以大幅提升效率頁在區(qū)內但不是相鄰的
: 可以大幅減少碰頭移動,可以提升效率頁在不同的區(qū)
: 還是要發(fā)生隨機I/0,不能提升效率
那么又有一個問題來了,新創(chuàng)建表時沒有數據,或者說有的表只有很少的數據,1MB的空間用不完,那不是就存在空間浪費的問題嗎?
- 是的,的確是這樣,InnoDB在設計時也考慮到了這個問題,我們繼續(xù)提出問題,然后再來解決。
5.4 當表中的數據很少時如何避免空間浪費?
通過 零散頁 和 碎片區(qū) 避免空間浪費的問題
- 當創(chuàng)建表時,并不知道當前表的數據量級
- 為了節(jié)省空間,最初只創(chuàng)建7個初始頁(在MySQL5.7中創(chuàng)建6個初始頁),而不是一個完整的區(qū),可以通過以下SOL查看:
mysql> select * FROM information_schema.INNODB_TABLESPACES WHERE name = 'test_db/student'\G *************************** 1. row *************************** SPACE: 9 NAME: test_db/student FLAG: 16417 ROW_FORMAT: Dynamic PAGE_SIZE: 16384 # 頁大小 ZIP_PAGE_SIZE: 0 SPACE_TYPE: Single FS_BLOCK_SIZE: 4096 FILE_SIZE: 114688 # 數據文件初始大小 ALLOCATED_SIZE: 114688 AUTOEXTEND_SIZE: 0 SERVER_VERSION: 8.0.42 SPACE_VERSION: 1 ENCRYPTION: N STATE: normal 1 row in set (0.00 sec) # 根據數據文件大小和每頁大小計算出頁數 # 114688 / 16348 = 7 個數據頁
這些零散頁會放在表空間中一個叫碎片區(qū)的區(qū)域,隨著數據量的增加,會申請新的頁來存儲數據,當碎片區(qū)達到 32個頁
的時候,后續(xù)每次都會申請 一個完整的區(qū)
來存儲更多的數據
?????六、如果訪問的數據跨區(qū)了怎么辦? - 區(qū)組
MySQL使用
Extent(區(qū))
這個結構來管理頁,規(guī)定每個區(qū)固定大小為 1MB ,可以存放 64 個頁
不同的區(qū)在磁盤上大概率是不連續(xù)的,那么這個問題其實是InnoDB如何高效的的管理區(qū)?
- 當表中的數據越來越多,為了有效的管理區(qū),定義了 區(qū)組 的結構,每個區(qū)組固定管理
256個區(qū)
即256MB
,通過區(qū)組可以在物理結構層面非常高效的管理和定位到每個區(qū)
第一個區(qū)組中的首個區(qū)的前四頁比特殊,也就是初始頁中的前4頁,分別是
File Space Header
: 表空間和區(qū)組中條目信息。Insert Buffer Bitmap
: Change Buffer相關信息。File Segmentinode
: 段信息。B-tree Node
: 索引根信息。- 其他為空閑頁用來存儲真實的數據
其他區(qū)組中首個區(qū)的結構都一樣,前兩個頁分別是:
Extent Descriptor(XDES)
: 區(qū)組條目信息Insert Buffer Bitmap
: Change Buffer相關信息
使用 區(qū)組
結構有效的管理區(qū),每個區(qū)組固定管理256個區(qū)即256MB,區(qū)組條目信息
中會記錄每個區(qū)的偏移并用雙向鏈表連接。
?????七、以上這些數據結構還有優(yōu)化的空間嗎? - 段
當然是有的,InnoDB使用"
段
"這個邏輯結構區(qū)分不同功能的區(qū)和在碎片區(qū)中的頁,并按功能分為"葉子節(jié)點段"和"非葉子節(jié)點段",做為B+樹索引中的葉子、非葉子節(jié)點,從而進一步提升查詢效怒。
以上講到的區(qū)、區(qū)組還有頁這種都是物理結構
在物理結構的基礎上,定義了一個邏輯上的概念,也就是"段
";
"段"并不對應表空間中的連續(xù)的物理區(qū)域,可以看做是"區(qū)"和"頁"的一個附加標注信息,段的主要作用是區(qū)分不同功能的區(qū)和在碎片區(qū)中的頁,主要分為"葉子節(jié)點段"和"非葉子節(jié)點段"等,這兩個段和我們常說的B+樹索引中的葉子、非葉子節(jié)點對應,
可以簡單的理解為
- “
非葉子節(jié)點段
” 存儲和管理索引樹 - “
葉子節(jié)點段
” 存儲和管理實際數據
從邏輯上講,最終由"葉子節(jié)點段"和"非葉子節(jié)點段"等段構成了表空間 .ibd 文件,如下圖所示:
?????八、延伸問題
8.1 上面講的所有操作是在哪里進行的?
- 所有的數據庫操作都是在
內存
中進行的,最終會把修改結果刷回磁盤中對應的頁
中。
8.2 查詢數據時 MySQL 會一次把表空間中的數據全部加載到內存嗎?
- 當然不是,使用
InnoDB
存儲引擎創(chuàng)建表,在查詢數據時會根據表空間內部定義的數據結構(一般為索引),定位到目標數據行所在的頁
,只把符合查詢要求的頁加載到內存。
8.3 每查詢一條數據都要進行一次磁盤I/0嗎?
- 不一定,每次查詢都會把磁盤中數據行對應的數據頁加載到內存中,如果當前查詢的數據行已經在內存中,則直接從內存中返回結果,從而提高查詢效率。
??總結
本篇博文對 【MySQL】表空間結構 - 從何為表空間到段頁詳解 做了一個較為詳細的介紹,不知道對你有沒有幫助呢
到此這篇關于MySQL表空間結構詳解表空間到段頁操作的文章就介紹到這了,更多相關mysql表空間結構內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用mysqladmin檢測MySQL運行狀態(tài)的教程
這篇文章主要介紹了使用mysqladmin檢測MySQL運行狀態(tài)的教程,包括mysqladmin工具簡單的awk使用,需要的朋友可以參考下2015-06-06