一、表的空間是怎么回收的?
InnoDB包含了兩個部分:表結構定義和數(shù)據(jù);在MySQL8.0前表結構是存在以.frm為后綴的文件里,8.0及之后已經允許放在系統(tǒng)數(shù)據(jù)表中,因為表結構占用空間很小。
1.怎么控制InnoDB表的表結構存放位置
innodb_file_per_table : MySQL5.6.6之后默認是ON
ON:每個InnDB的表數(shù)據(jù)存在一個以.ibd為后綴的文件中;
OFF:表的數(shù)據(jù)放在系統(tǒng)共享表空間,也就是跟數(shù)據(jù)字典放在一起;
建議設置
建議設置為ON,因為如果需要刪除表,設置為ON,執(zhí)行drop table 命令也會刪除.ibd文件,會回收表結構的空間;設置為OFF雖然把表刪了也不會回收表結構的空間。
2.數(shù)據(jù)的刪除流程
DQL(查詢):查詢數(shù)據(jù):select語句(最常用)
DML(操縱):表數(shù)據(jù)的增刪改,insert、update、delete
DDL(定義):對表的增刪改,create、drop、alter
DCL(控制):grant授權、revoke撤消等
TCL(事務控制):commit事務提交、rollback回滾事務
(1)什么叫數(shù)據(jù)的“空洞”?
數(shù)據(jù)在刪除的時候,表結構InnDB的索引是以B+tree的形式儲存的,當刪除某個數(shù)據(jù)時,只會把該子葉子節(jié)點的數(shù)據(jù)標記,不會立即釋放空間,只有有一條記錄的索引等于該值時才會復用這個位置。
我們直到mysql都是以數(shù)據(jù)頁的形式儲存的,如果整個數(shù)據(jù)頁都被標記,那么新增數(shù)據(jù)在該數(shù)據(jù)頁的范圍值內,就可以直接復用。
當相鄰兩個數(shù)據(jù)頁的數(shù)據(jù)都比較少時,兩個數(shù)據(jù)頁的數(shù)據(jù)會合在一起,騰出一個新的數(shù)據(jù)頁被標記為可復用。
delete命令刪除表時,都會把刪除的位置標記,認為是可復用,我們把那些沒有被復用到的位置稱為空洞。
(2)怎么解決空洞問題呢?
重建表
2.怎么重建表?
用語句:
alert table t engine=InnoDB
(1)請簡述重建表的過程:
在MySQL5.6之后,重建表支持Online DDL(在重建表時,可以有DDL操作)的操作:
- 建立一個臨時文件,記錄掃描表t的數(shù)據(jù)頁
- 用數(shù)據(jù)頁表t的記錄生成B+tree,記錄臨時文件
- 在生成記錄臨時文件的過程中,對表t的操作記錄到日志文件 row log,
-把row log日志文件的記錄寫入到臨時文件的得到邏輯上與表t相同的文件 - 用臨時文件把表t替換
(2)DDL 之前是要拿 MDL 寫鎖的,這樣還能叫 Online DDL 嗎?
在執(zhí)行alert之后是會獲取MDL寫鎖的,但是在復制數(shù)據(jù)的時候會退化成MDL讀鎖,這個時候是可以修改數(shù)據(jù)的。
為什么不直接放開MDL鎖呢?
因為要禁止其它線程對表DDL
所以在整個DDL過程來說,鎖的時間非常短,所以可以看做是Online DDL
(3)在生產中一般怎么使用
在生產中一般數(shù)據(jù)量比較大的數(shù)據(jù)庫來說的話,因為會對整個表掃描和建立臨時文件是非常消耗io和cpu的,建議使用Githud開源的gh-ost
gh-ost是什么?
是一個開源的縮小表空間的工具。
3.DDL online 和 inplace的區(qū)別
DDL online和inplace是包含與被包含的關系,online一定是inplace,反之亦然。截止到 MySQL 8.0,添加全文索引(FULLTEXT index)和空間索引 (SPATIAL index) 就屬于這種情況
alter table t add FULLTEXT(field_name);
這個過程是 inplace 的,但會阻塞增刪改操作,是非 Online 的。
二、思考題
假設現(xiàn)在有人碰到了一個“想要收縮表空間,結果適得其反”的情況,看上去是這樣的:一個表 t 文件大小為 1TB;對這個表執(zhí)行 alter table t engine=InnoDB;發(fā)現(xiàn)執(zhí)行完成后,空間不僅沒變小,還稍微大了一點兒,比如變成了 1.01TB。你覺得可能是什么原因呢 ?