成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇學(xué)會(huì) InnoDB 表空間

網(wǎng)絡(luò) 通信技術(shù)
我們存在 MySQL 中的數(shù)據(jù),到底在磁盤上長(zhǎng)啥樣。你可能會(huì)說(shuō),數(shù)據(jù)不都存儲(chǔ)在聚簇索引中嗎?但很遺憾,你并沒(méi)有回答我的問(wèn)題。我會(huì)再問(wèn)你,那聚簇索引在磁盤上又長(zhǎng)啥樣?

[[408831]]

本文轉(zhuǎn)載自微信公眾號(hào)「SH的全棧筆記」,作者SH的全棧筆記。轉(zhuǎn)載本文請(qǐng)聯(lián)系SH的全棧筆記公眾號(hào)。

想了很久的標(biāo)題,算了,就這樣吧。

這應(yīng)該是 MySQL 原理中最底層的部分了,我們存在 MySQL 中的數(shù)據(jù),到底在磁盤上長(zhǎng)啥樣。你可能會(huì)說(shuō),數(shù)據(jù)不都存儲(chǔ)在聚簇索引中嗎?但很遺憾,你并沒(méi)有回答我的問(wèn)題。我會(huì)再問(wèn)你,那聚簇索引在磁盤上又長(zhǎng)啥樣?

就像 Redis 的 RDB 文件,最終落在磁盤上就是一個(gè)真真切切的 dump.rdb 文件,而 MySQL 就顯得有點(diǎn)迷,我們只知道通過(guò) SQL 去拿數(shù)據(jù),并不知道數(shù)據(jù)最終是以什么方式進(jìn)行存儲(chǔ)的。當(dāng)然,了解其底層的存儲(chǔ)邏輯,并不僅僅是為了滿足好奇心這么簡(jiǎn)單。

其底層的存儲(chǔ)方式,會(huì)影響到聚簇索引中數(shù)據(jù)的存儲(chǔ),進(jìn)而影響到 MySQL 的 DML(Data Manipulation Language) 性能,所以對(duì)底層存儲(chǔ)邏輯有個(gè)清晰的認(rèn)知,就能夠在某些對(duì)性能有著極致追求的場(chǎng)景下,幫助我們對(duì) MySQL 進(jìn)行優(yōu)化。

表在磁盤上到底長(zhǎng)啥樣

首先我們先不扯像表空間這類的專業(yè)詞匯,讓我們先來(lái)建一張表,從磁盤的結(jié)構(gòu)上來(lái)看一下。首先你得找到 MySQL 的數(shù)據(jù)目錄,如果你是用 Docker 啟動(dòng)的話,這個(gè)目錄大概長(zhǎng)下面這樣:

  1. /data00/docker/volumes/ef876f70d5f5c95325c2a79689db79cc4d1cecb7d96e98901256bd49ca359287/_data 

然后我們新建一個(gè)叫 test 的 DB,然后在 _data 的這個(gè)目錄下就會(huì)多一個(gè) test 的目錄。然后在 test 數(shù)據(jù)庫(kù)下新建了一張 student 的表,在 test 目錄下就會(huì)多出兩個(gè)文件,分別是 student.frm 和 student.ibd。

可以發(fā)現(xiàn),最終數(shù)據(jù)在磁盤上的宏觀表現(xiàn)其實(shí)很簡(jiǎn)單,就這么些個(gè)文件,什么索引啊、頁(yè)啊都先忽略不管。

對(duì)于后綴為 .frm 文件,里面都有啥?里面包含了每張表的元數(shù)據(jù),包括了表的結(jié)構(gòu)定義。而 .ibd 文件里則存放了該表的數(shù)據(jù)和索引。

我看到有人在博客里把 .ibd 寫成了 .idb...雖然 db 看著更順,但很遺憾并不正確,你把 ibd 的全稱 innodb data 記住,就不會(huì)把縮寫記錯(cuò)了。

上面說(shuō)的這個(gè)以表名命名的 ibd 文件,其實(shí)還有一個(gè)專業(yè)術(shù)語(yǔ)叫表空間。

顧名思義可以理解為我這個(gè)表專屬的空間。

認(rèn)識(shí)表空間

如果我上來(lái)就直接告訴你,InnoDB 中有個(gè)概念叫表空間,你大概率是很難理解的。

像上文描述的這種每張表都有自己?jiǎn)为?dú)的數(shù)據(jù)存儲(chǔ)文件的,叫獨(dú)占表空間;相對(duì)應(yīng)的,InnoDB 還有自己的系統(tǒng)表空間,在系統(tǒng)表空間下,所有表的數(shù)據(jù)都存儲(chǔ)在同一個(gè)文件中。

那數(shù)據(jù)什么時(shí)候存儲(chǔ)在系統(tǒng)表空間,又什么時(shí)候存儲(chǔ)在獨(dú)占表空間呢?

這個(gè)可以通過(guò) MySQL 的配置項(xiàng) innodb_file_per_table 來(lái)決定。當(dāng)該配置項(xiàng)開(kāi)啟時(shí),每張表都會(huì)有自己?jiǎn)为?dú)的表空間;相反,當(dāng)該配置項(xiàng)關(guān)閉時(shí),表數(shù)據(jù)將會(huì)存儲(chǔ)在系統(tǒng)的表空間內(nèi)。

該配置項(xiàng)是默認(rèn)開(kāi)啟的,你可以在 MySQL 中通過(guò)命令 SHOW VARIABLES LIKE 'innodb_file_per_table' 來(lái)查看該變量的狀態(tài)。

其實(shí)從 MySQL 將獨(dú)占表空間作為默認(rèn)的設(shè)置來(lái)看,你就應(yīng)該知道獨(dú)占表空間的性能肯定是要比系統(tǒng)表空間好的。

因?yàn)閷?duì)于系統(tǒng)表空間來(lái)說(shuō),通常只有一個(gè)文件,所有的表數(shù)據(jù)都在這一個(gè)文件中,如果我們對(duì)某張表進(jìn)行 TRUNCATE 操作,需要將分散在文件中各個(gè)地方的數(shù)據(jù)刪除。首先這樣做性能就不好,其次 TRUNCATE 操作會(huì)在該文件中產(chǎn)生很多空閑的碎片空間,并且并不會(huì)減少共享表空間文件 ibdata1 的大小。

不能理解的話,可以想象 Java 里的標(biāo)記-清理垃圾回收算法,該算法會(huì)在清理的時(shí)候造成大量的內(nèi)存碎片,不利于提高后期的內(nèi)存利用率。

而對(duì)于獨(dú)占表空間來(lái)說(shuō),從始至終一整張表的數(shù)據(jù)都只存儲(chǔ)在一個(gè)文件,比起共享表空間誰(shuí)更容易清理并且還能釋放磁盤空間,簡(jiǎn)直是一目了然。所以,對(duì)于獨(dú)占表空間來(lái)說(shuō),TRUNCATE 的性能會(huì)更好。

除此之外,獨(dú)占表空間能夠提升單張表的最大容量限制,這塊可能不是很好理解,為什么獨(dú)占表空間還有這個(gè)功效?在這里你只需要記住這個(gè)結(jié)論就好了,后文講到頁(yè)相關(guān)的東西時(shí),我們會(huì)具體的論證。

了解了表空間的概念之后,我們就可以繼續(xù)深入了解數(shù)據(jù)在表空間內(nèi)到底是怎么存儲(chǔ)的了。

深入表空間文件內(nèi)部

其實(shí)在很早之前我講 InnoDB的內(nèi)存架構(gòu) 時(shí)我就講過(guò),在 InnoDB 中,頁(yè)是其數(shù)據(jù)管理的最小單位。所以講道理我們應(yīng)該從其最小的部分開(kāi)始,但是之前已經(jīng)專門寫過(guò)一篇文章來(lái)討論頁(yè)了,所以在這里就不贅述了。

表空間由一堆的**頁(yè)(Pages)**組成,并且每張頁(yè)的大小是相等的,頁(yè)大小默認(rèn)為 16K,當(dāng)然這個(gè)大小可以調(diào)整。

頁(yè)大小可以通過(guò)配置項(xiàng) innodb_page_size 根據(jù)業(yè)務(wù)的實(shí)際情況進(jìn)行調(diào)整,可以選擇的大小分別為 4K、8K、16K、32K和64K。

一堆頁(yè)組合在一起,就變成了區(qū)(Extents)。

每個(gè)區(qū)的大小是固定的。當(dāng)我們?cè)O(shè)置了不同的 innodb_page_size 時(shí),每個(gè)區(qū)(Extents)內(nèi)所包含的頁(yè)的數(shù)量、和對(duì)應(yīng)的固定區(qū)大小都不同,具體的情況如下圖所示。

當(dāng) innodb_page_size 為 4K、8K或者16K時(shí),其對(duì)應(yīng)的區(qū)(Extents)大小為1M;當(dāng)其頁(yè)大小為32K時(shí),區(qū)大小為2M;當(dāng)頁(yè)大小為64K時(shí),區(qū)大小為4M。

MySQL 5.6的時(shí)候其實(shí)只支持 4K、8K和16K,至于上面說(shuō)到的32K和64K,是在 MySQL 5.7.6 之后添加的。

隨著頁(yè)和區(qū)大小的變動(dòng),每個(gè)區(qū)內(nèi)所能容納的 頁(yè)數(shù)量 也會(huì)隨之改變。舉個(gè)例子,當(dāng) innodb_page_size 的值為 16K 時(shí),每個(gè)區(qū)就包含 64 頁(yè);當(dāng)其為 8K 時(shí),每個(gè)區(qū)包含 128 頁(yè);當(dāng)其為 4K 時(shí),每個(gè)區(qū)就會(huì)包含 256 頁(yè)。

上面聊過(guò),一頁(yè)一頁(yè)的數(shù)據(jù)組成了區(qū),而一個(gè)一個(gè)區(qū)則組成了段(Segments)。

在邏輯上,InnoDB 的表空間就是由一個(gè)一個(gè)這樣的段(Segment)組成的。隨著數(shù)據(jù)量的持續(xù)增長(zhǎng)需要申請(qǐng)新的空間時(shí),InnoDB 會(huì)先請(qǐng)求32個(gè)頁(yè),之后便會(huì)直接分配一整個(gè)區(qū)(Extents) 。甚至在某個(gè)很大的 Segment 內(nèi),還會(huì)一次性分配 4 個(gè)區(qū)。

默認(rèn)情況下,InnoDB 會(huì)給每個(gè)索引分配兩個(gè)段(Segment)。一個(gè)用于存儲(chǔ)索引中的非葉子結(jié)點(diǎn),另一個(gè)用于存儲(chǔ)葉子結(jié)點(diǎn)。

表空間的分類

上面大概介紹了兩種表空間類別,分別是系統(tǒng)表空間、獨(dú)占表空間。接下來(lái)就需要詳細(xì)的了解一下各個(gè)表空間分類的細(xì)節(jié)了。

系統(tǒng)表空間

當(dāng)我們開(kāi)啟了innodb_file_per_table 這個(gè)配置項(xiàng)(默認(rèn)就是開(kāi)啟的)之后,系統(tǒng)表空間內(nèi)就只用于存儲(chǔ) Change Buffer 相關(guān)的數(shù)據(jù)。而當(dāng)我們將其關(guān)閉之后,系統(tǒng)表空間內(nèi)就會(huì)存儲(chǔ)表和索引相關(guān)的數(shù)據(jù)。當(dāng)然,在 MySQL 8.0之前,獨(dú)占表空間內(nèi)還包含了 Double Write Buffer(兩次寫緩沖),但在 MySQL 8.0.20 之后被移了出去,存放在了一個(gè)單獨(dú)的文件中。

默認(rèn)情況下,系統(tǒng)表空間只會(huì)有一個(gè)叫 ibdata1 的數(shù)據(jù)文件,當(dāng)然,它是允許有多個(gè)文件存在的。這所有的屬性包括文件名稱、文件大小都是通過(guò)配置項(xiàng)目 innodb_data_file_path 來(lái)制定的,舉個(gè)例子:

  1. innodb_data_file_path=ibdata1:10M:autoextend 

這里指明了系統(tǒng)表空間的文件名為ibdata1 ,初始化大小為10M 。你可發(fā)現(xiàn)了,這個(gè) autoextend 是個(gè)什么鬼?

剛剛說(shuō)到,初始大小是 10M ,那么隨著 MySQL 的運(yùn)行,其數(shù)據(jù)量會(huì)慢慢的增長(zhǎng),數(shù)據(jù)文件必須要申請(qǐng)更多的空間來(lái)存儲(chǔ)數(shù)據(jù)。而定義了 autoextend InnoDB 就會(huì)幫我們自動(dòng)對(duì)數(shù)據(jù)文件進(jìn)行擴(kuò)容,每次擴(kuò)容申請(qǐng) 8M 的空間。當(dāng)然,這個(gè) 8M 也是可以配置的,我們可以通過(guò)配置項(xiàng) innodb_autoextend_increment 來(lái)配置。

獨(dú)占表空間

這塊其實(shí)上面在引入的時(shí)候已經(jīng)介紹的差不多了,這里簡(jiǎn)單的總結(jié)一下就好。當(dāng)配置項(xiàng) innodb_file_per_table 開(kāi)啟時(shí)(現(xiàn)在是默認(rèn)開(kāi)啟的),每張表的數(shù)據(jù)都會(huì)存儲(chǔ)自己?jiǎn)为?dú)的數(shù)據(jù)文件中。

常規(guī)表空間

這個(gè)暫時(shí)不用了解,知道常規(guī)表空間跟系統(tǒng)表空間類似,也是一個(gè)共享的存儲(chǔ)空間就好。

Undo 表空間

這里主要存儲(chǔ) Undo Logs,有了 Undo Logs 我們就可以在事務(wù)出錯(cuò)之后快速的將更改回滾。InnoDB 會(huì)默認(rèn)給 Undo 表空間創(chuàng)建兩個(gè)數(shù)據(jù)文件,如果沒(méi)有特別指定,其文件名默認(rèn)為 undo_001 和 undo_002 。

至于這兩個(gè)數(shù)據(jù)文件的具體存放路徑,可以通過(guò)配置項(xiàng) innodb_undo_directory 來(lái)指定。當(dāng)然,如果沒(méi)有指定,Undo 表空間的數(shù)據(jù)文件就會(huì)放在 InnoDB 的默認(rèn)數(shù)據(jù)目錄下,通常來(lái)說(shuō)是 /usr/local/mysql 。

而這兩個(gè) Undo 表空間數(shù)據(jù)文件的初始大小,在 MySQL 8.0.23 之前是由 InnoDB 的頁(yè)大小來(lái)決定的,具體的情況如下圖:

而在 MySQL 8.0.23 之后,Undo 表空間的初始化大小都是 16M 了。至于 Undo 表空間的擴(kuò)容,不同的版本也有不通的處理方式。

在 MySQL 8.0.23 之前,每次擴(kuò)容是申請(qǐng) 4 個(gè)區(qū)(Extends),按照之前的討論,如果頁(yè)大小為 16 K,那么對(duì)應(yīng)到區(qū)就是 1M,換句話說(shuō),每次擴(kuò)容申請(qǐng) 4M 的空間,當(dāng)然這個(gè)具體的大小會(huì)根據(jù)頁(yè)大小的變化而變化,這個(gè)在上文提到過(guò)在此就不再贅述。

而在 MySQL 8.0.23 之后,每次最少都要擴(kuò)容 16 M的空間。而且,為了防止數(shù)據(jù)量爆發(fā)式的增長(zhǎng),InnoDB 對(duì)擴(kuò)容的容量會(huì)做一個(gè)動(dòng)態(tài)的調(diào)整。

如果本次擴(kuò)容和上次擴(kuò)容時(shí)間差小于 0.1 秒,則擴(kuò)容的空間會(huì)加倍,也就是變成 32 M。如果多次擴(kuò)容的時(shí)間差都小于 0.1 秒,這個(gè) 加倍 的操作會(huì) 累加,直到達(dá)到上限 256M;那你可能會(huì)說(shuō),那如果某段時(shí)間剛好請(qǐng)求量比較大,使得擴(kuò)容的容量達(dá)到了最大的 256 M,那后續(xù)請(qǐng)求量下去了呢?難道還是申請(qǐng) 256 M嗎?這顯的不太合理。所以 InnoDB 判斷如果兩次擴(kuò)容間隔大于 0.1 秒,就會(huì)將擴(kuò)容的容量減半,直到減少到最小限制 16 M。

臨時(shí)表空間

臨時(shí)表空間內(nèi)的數(shù)據(jù),顧名思義都是臨時(shí)的。

你在說(shuō)屁話...

它分為兩個(gè)部分,分別是:

  • Session 臨時(shí)表空間
  • 全局臨時(shí)表空間

對(duì)于 Session 臨時(shí)表空間,里面會(huì)存儲(chǔ)由用戶或者優(yōu)化器創(chuàng)建的臨時(shí)表。對(duì)于每個(gè) Session 來(lái)說(shuō),InnoDB 最多會(huì)分配兩個(gè)數(shù)據(jù)文件(表空間),分別用于存儲(chǔ)用戶創(chuàng)建的臨時(shí)表和優(yōu)化器創(chuàng)建的內(nèi)部臨時(shí)表。當(dāng) Session 失效之后,這些已分配的數(shù)據(jù)文件會(huì)被 Truncate 然后放到一個(gè) 數(shù)據(jù)文件池 中。

這個(gè)操作其實(shí)跟其他的池化技術(shù)沒(méi)有區(qū)別,值得注意的是,這些文件被 Truncate 了之后大小并不會(huì)發(fā)生變化。而這個(gè)數(shù)據(jù)文件池會(huì)在 MySQL 服務(wù)器啟動(dòng)的時(shí)候創(chuàng)建,里面會(huì)默認(rèn)扔進(jìn)去 10 個(gè)文件,每個(gè)文件的默認(rèn)大小為 5 頁(yè)。

而對(duì)于全局臨時(shí)表空間,里面會(huì)存對(duì)臨時(shí)表做了改動(dòng)的回滾段(Rollback Segment),其初始化的大小大約是 12 M,同樣會(huì)在 MySQL 服務(wù)器啟動(dòng)的時(shí)候創(chuàng)建。

 

責(zé)任編輯:武曉燕 來(lái)源: SH的全棧筆記
相關(guān)推薦

2021-09-07 17:54:04

OpenGauss分區(qū)表索引

2022-06-22 07:32:53

Sharding分庫(kù)數(shù)據(jù)源

2022-01-02 08:43:46

Python

2022-02-07 11:01:23

ZooKeeper

2022-08-29 08:00:11

哈希表數(shù)組存儲(chǔ)桶

2021-05-11 08:54:59

建造者模式設(shè)計(jì)

2021-07-06 08:59:18

抽象工廠模式

2023-01-03 08:31:54

Spring讀取器配置

2021-07-05 22:11:38

MySQL體系架構(gòu)

2023-11-28 08:29:31

Rust內(nèi)存布局

2022-08-26 09:29:01

Kubernetes策略Master

2022-08-23 08:00:59

磁盤性能網(wǎng)絡(luò)

2021-07-02 08:51:29

源碼參數(shù)Thread

2021-09-28 08:59:30

復(fù)原IP地址

2021-10-14 10:22:19

逃逸JVM性能

2022-04-12 08:30:52

回調(diào)函數(shù)代碼調(diào)試

2021-10-27 09:59:35

存儲(chǔ)

2021-07-16 22:43:10

Go并發(fā)Golang

2023-03-13 21:38:08

TCP數(shù)據(jù)IP地址

2023-11-01 09:07:01

Spring裝配源碼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 中文字幕日韩一区二区 | 一区二区三区视频在线免费观看 | 操人网站| 国产一级视频在线观看 | 色婷婷av久久久久久久 | 国产精品欧美一区二区三区不卡 | 亚洲欧美日本国产 | 国产精品视频在线播放 | 在线观看www | 人人爽人人草 | 另类专区亚洲 | 男女羞羞在线观看 | 成人精品一区二区 | 中文字幕日韩欧美一区二区三区 | 日韩在线观看网站 | 亚洲欧美日韩一区二区 | 神马九九| 欧美在线a | 国产69久久精品成人看动漫 | 一区二区精品电影 | 欧美一区免费 | 国产激情网站 | 四虎网站在线观看 | 精品一区精品二区 | 亚洲日本欧美日韩高观看 | 成人三级影院 | 亚洲高清视频一区二区 | 国产午夜精品一区二区三区四区 | 久久中文网 | 91久久久久久久久久久久久 | 中文字幕精品一区二区三区精品 | 户外露出一区二区三区 | av国产精品毛片一区二区小说 | 亚洲资源站 | 中文字幕在线观看一区二区 | 精品国产乱码久久久久久丨区2区 | 久久久久国产精品免费免费搜索 | 亚洲一区中文字幕 | 国产亚洲欧美另类一区二区三区 | 青娱乐一区二区 | 日韩一区二区三区视频 |