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