MySQL 表空間碎片的概念及相關(guān)問(wèn)題解決
背景
經(jīng)常使用 MySQL 的話,會(huì)發(fā)現(xiàn) MySQL 數(shù)據(jù)文件的磁盤空間一般會(huì)不停的增長(zhǎng),而且有時(shí)候刪了數(shù)據(jù)或者插入一批數(shù)據(jù)的時(shí)候,磁盤空間有時(shí)候還會(huì)毫無(wú)變化。引發(fā)這個(gè)其妙現(xiàn)象的就是 MySQL 的表空間碎片。
什么是表空間碎片?
表空間碎片指的是表空間中存在碎片,形象一點(diǎn)來(lái)比喻的話,就像是一張 A4 紙,“表空間碎片”就像是把這張 A4 紙撕碎,再重新拼起來(lái),各個(gè)碎片之間都會(huì)有一些縫隙存在,這些縫隙就是“表空間碎片”。重新拼起來(lái)的碎片實(shí)際上會(huì)比完整的 A4 紙大上一圈,這也代表著表空間容易引發(fā)的問(wèn)題:空間浪費(fèi)。
對(duì)于背景中描述的現(xiàn)象,可以用一張圖來(lái)進(jìn)行解釋:
圖中的數(shù)字代表真實(shí)的數(shù)據(jù)行,圓角矩形代表一個(gè)表的表空間。從左往右,第一次操作是刪除數(shù)據(jù),由于 MySQL 在設(shè)計(jì)上是不會(huì)主動(dòng)釋放空間的,因此當(dāng)表中的數(shù)據(jù)行被刪除時(shí),雖然數(shù)據(jù)被“刪除”了,但是實(shí)際上這部分空間是沒(méi)有釋放的,依舊會(huì)被 Table A 占用,因此也就出現(xiàn)了這樣子的情景:刪除了日志表的很多數(shù)據(jù),但是 MySQL 的磁盤空間并沒(méi)有降低。
PS:這種不釋放空間的設(shè)計(jì)多半和惰性刪除有關(guān),早期設(shè)計(jì)數(shù)據(jù)庫(kù)時(shí),使用的 IO 設(shè)備一般是機(jī)械盤,讀寫性能比 SSD 差很多,所以刪除操作一般不會(huì)直接觸發(fā)磁盤上的數(shù)據(jù)刪除。
可以看到數(shù)據(jù)刪除之后,原本連續(xù)的空間中出現(xiàn)了兩個(gè)空白的區(qū)域,這種一般就叫做表空間空洞,空洞太多了就叫做表空間碎片化(對(duì)應(yīng)的是表空間連續(xù))。這部分的空間雖然不會(huì)釋放,但是會(huì)被標(biāo)記為可重復(fù)利用,參考最右邊的表空間示意圖(第三個(gè)圓角矩形),當(dāng)新插入數(shù)據(jù)的時(shí)候新數(shù)據(jù)會(huì)重新寫入到表空間空洞中,這也代表著:在大規(guī)模刪除過(guò)數(shù)據(jù)的表上,寫入數(shù)據(jù)時(shí),表空間可能不會(huì)明顯增長(zhǎng)或者不會(huì)增長(zhǎng)。
實(shí)際上產(chǎn)生表空間空洞的操作并不只有 delete,update 也會(huì)引起這個(gè)問(wèn)題,比如在 varchar 這種變長(zhǎng)的字符型列中修改數(shù)據(jù),改短一些的時(shí)候就會(huì)出現(xiàn)非常小的空洞,改長(zhǎng)的話就有可能會(huì)因?yàn)榭臻g不足導(dǎo)致把數(shù)據(jù)行的一些數(shù)據(jù)遷移到其他地方去。
怎么查看表空間碎片
MySQL 的系統(tǒng)表記錄了表空間的使用情況,可以用如下查詢檢查:
SELECT CONCAT(table_schema,'.',table_name) AS 'table_name', table_rows AS 'Number of Rows', CONCAT(ROUND(data_length/(1024*1024),2),' M') AS 'data_size', CONCAT(ROUND(index_length/(1024*1024),2),' M') AS 'index_size' , CONCAT(ROUND(data_free/(1024*1024),2),' M') AS'data_free', CONCAT(ROUND(data_free/data_length,2),' %') AS 'data_free_pct', ENGINE as 'engine' FROM information_schema.TABLES WHERE table_schema = 'tablename' ORDER by data_free desc;
data_free 指表空間碎片的總空間大小,data_free_pct 指這個(gè)表的碎片百分比,效果如下:
mysql> SELECT CONCAT(table_schema,'.',table_name) AS 'table_name', -> table_rows AS 'Number of Rows', -> CONCAT(ROUND(data_length/(1024*1024),2),' M') AS 'data_size', -> CONCAT(ROUND(index_length/(1024*1024),2),' M') AS 'index_size' , -> CONCAT(ROUND(data_free/(1024*1024),2),' M') AS'data_free', -> CONCAT(ROUND(data_free/data_length,2),' %') AS 'data_free_pct', -> ENGINE as 'engine' -> FROM information_schema.TABLES -> WHERE table_schema = 'sbtest' -> ORDER by data_free desc; +----------------+----------------+-----------+------------+-----------+---------------+--------+ | table_name | Number of Rows | data_size | index_size | data_free | data_free_pct | engine | +----------------+----------------+-----------+------------+-----------+---------------+--------+ | sbtest.sbtest5 | 0 | 0.02 M | 0.00 M | 44.00 M | 2816.00 % | InnoDB | | sbtest.sbtest4 | 986400 | 214.70 M | 15.52 M | 4.00 M | 0.02 % | InnoDB | | sbtest.sbtest3 | 986400 | 214.70 M | 15.52 M | 4.00 M | 0.02 % | InnoDB | | sbtest.sbtest2 | 986400 | 214.70 M | 15.52 M | 4.00 M | 0.02 % | InnoDB | | sbtest.sbtest1 | 987400 | 199.70 M | 15.52 M | 4.00 M | 0.02 % | InnoDB | +----------------+----------------+-----------+------------+-----------+---------------+--------+ 5 rows in set (0.00 sec)
第一行數(shù)據(jù)是測(cè)試用的數(shù)據(jù),表中的所有數(shù)據(jù)都被刪掉了,因此計(jì)算出來(lái)的 data_free_pct 超過(guò)了 100%。
怎么解決表空間碎片問(wèn)題
目前,能夠回收表空間的辦法僅有一個(gè),就是重建表,手段包括但不限于 optimize,alter table 等。alter table 的有些操作只能靠 rebuild 表來(lái)完成,所以有時(shí)候?qū)Υ蟊磉M(jìn)行一些維護(hù)操作之后,也會(huì)看到磁盤空間使用率下降,這就是回收了表空間碎片騰出來(lái)的那一部分空間。
從一般經(jīng)驗(yàn)來(lái)看,表空間碎片的回收操作不建議經(jīng)常執(zhí)行,每個(gè)月一次就足夠了,因?yàn)?rebuild 表對(duì)服務(wù)器的資源影響會(huì)比較大,且會(huì)影響這個(gè)表的寫入操作。碎片率(data_free_pct)低于 20% 的時(shí)候也不用特別在意,除非磁盤空間非常緊張,且日志基本被清空。
對(duì)于回收空間的問(wèn)題
對(duì)一些日志表,或者是有區(qū)域性特征的表,建議使用 MySQL 的分區(qū)表來(lái)管理,需要清理一批數(shù)據(jù)的時(shí)候,可以用 partition truncate 的方式進(jìn)行清理,磁盤空間也能直接釋放掉。
以上就是MySQL 表空間碎片的概念及相關(guān)問(wèn)題解決的詳細(xì)內(nèi)容,更多關(guān)于MySQL 表空間碎片的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
MySQL基于DOS命令行登錄操作實(shí)例(圖文說(shuō)明)
這篇文章主要介紹了MySQL基于DOS命令行登錄操作,以圖文形式結(jié)合實(shí)例說(shuō)明了MySQL登錄命令的基本用法,非常簡(jiǎn)單易懂需要的朋友可以參考下2016-01-01mysql導(dǎo)入sql文件命令和mysql遠(yuǎn)程登陸使用詳解
這篇文章主要介紹了mysql導(dǎo)入sql文件命令和mysql遠(yuǎn)程登陸使用詳解,需要的朋友可以參考下2014-04-04docker下mysql 8.0.20 安裝配置方法圖文教程
這篇文章主要介紹了docker下mysql 8.0.20 安裝配置方法圖文教程,文中安裝步驟介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05MySQL報(bào)錯(cuò)?:Error?writing?file?‘/tmp/XXXX‘?(Errcode:?28?
這篇文章主要給大家介紹了MySQL報(bào)錯(cuò)解決:Error?writing?file?‘/tmp/XXXX‘?(Errcode:?28?-?No?space?left?on?device),文中通過(guò)代碼示例和圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10Docker搭建MySQL并掛載數(shù)據(jù)的全過(guò)程
環(huán)境搭建費(fèi)時(shí)費(fèi)力,但要必不可少,這篇文章主要給大家介紹了關(guān)于Docker搭建MySQL并掛載數(shù)據(jù)的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01mysql存儲(chǔ)過(guò)程中使用游標(biāo)的實(shí)例
使用MYSQL存儲(chǔ)過(guò)程,可以實(shí)現(xiàn)諸多的功能,下面將為您介紹一個(gè)MYSQL存儲(chǔ)過(guò)程中使用游標(biāo)的實(shí)例2014-01-01mysql5.7.18安裝時(shí)提示無(wú)法找到入口問(wèn)題的解決方法
這篇文章主要為大家詳細(xì)介紹了mysql5.7.18安裝時(shí)出現(xiàn)無(wú)法找到入口問(wèn)題的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04