一湾笛、參數(shù)innodb_file_per_table:
??表數(shù)據(jù)既可以存在共享表空間里饮怯,也可以是單獨(dú)的文件。這個(gè)行為是由參數(shù)innodb_file_per_table控制的:
這個(gè)參數(shù)設(shè)置為OFF表示的是嚎研,表的數(shù)據(jù)放在系統(tǒng)共享表空間蓖墅,也就是跟數(shù)據(jù)字典放在一起;
這個(gè)參數(shù)設(shè)置為ON表示的是临扮,每個(gè)InnoDB表數(shù)據(jù)存儲(chǔ)在一個(gè)以 .ibd為后綴的文件中论矾。
從MySQL 5.6.6版本開始,它的默認(rèn)值就是ON了杆勇。
建議不論使用MySQL的哪個(gè)版本贪壳,都將這個(gè)值設(shè)置為ON。因?yàn)椋?strong>一個(gè)表單獨(dú)存儲(chǔ)為一個(gè)文件更容易管理靶橱,而且不需要這個(gè)表的時(shí)候寥袭,通過drop table命令路捧,系統(tǒng)就會(huì)直接刪除這個(gè)文件。而如果是放在共享表空間中传黄,即使表刪掉了杰扫,空間也是不會(huì)回收的。
二膘掰、數(shù)據(jù)刪除流程:
??InnoDB的數(shù)據(jù)是按頁存儲(chǔ)的章姓,那么如果刪掉了一個(gè)數(shù)據(jù)頁上的所有記錄,那么整個(gè)數(shù)據(jù)頁就可以被復(fù)用了识埋。但是凡伊,數(shù)據(jù)頁的復(fù)用跟記錄的復(fù)用是不同的。記錄的復(fù)用窒舟,只限于符合范圍條件的數(shù)據(jù)系忙。而當(dāng)整個(gè)頁從B+樹里面摘掉以后,可以復(fù)用到任何位置惠豺。如果相鄰的兩個(gè)數(shù)據(jù)頁利用率都很小银还,系統(tǒng)就會(huì)把這兩個(gè)頁上的數(shù)據(jù)合到其中一個(gè)頁上,另外一個(gè)數(shù)據(jù)頁就被標(biāo)記為可復(fù)用洁墙。如果我們用delete命令把整個(gè)表的數(shù)據(jù)刪除蛹疯,所有的數(shù)據(jù)頁都會(huì)被標(biāo)記為可復(fù)用。但是磁盤上热监,文件不會(huì)變小捺弦。因?yàn)?strong>delete命令其實(shí)只是把記錄的位置,或者數(shù)據(jù)頁標(biāo)記為了“可復(fù)用”孝扛,但磁盤文件的大小是不會(huì)變的列吼。也就是說,通過delete命令是不能回收表空間的疗琉。這些可以復(fù)用冈欢,而沒有被使用的空間歉铝,看起來就像是“空洞”盈简。實(shí)際上,不止是刪除數(shù)據(jù)會(huì)造成空洞太示,插入數(shù)據(jù)也會(huì)柠贤。如果數(shù)據(jù)是按照索引遞增順序插入的,那么索引是緊湊的类缤。但如果數(shù)據(jù)是隨機(jī)插入的(而且插入的數(shù)據(jù)是在該數(shù)據(jù)頁的數(shù)據(jù)范圍之內(nèi)臼勉,比如說PageA中的數(shù)據(jù)是從0到10,此時(shí)嵌纲,數(shù)據(jù)頁雖然有未被使用的空間盛险,但由于數(shù)據(jù)頁的頭和尾都被插入了數(shù)據(jù),所以再插入8的時(shí)候实愚,就會(huì)把8~10的數(shù)據(jù)移到另一個(gè)數(shù)據(jù)頁中瓢谢,同時(shí)將之前的數(shù)據(jù)頁中移過來的數(shù)據(jù)標(biāo)為可復(fù)用)畸写,就可能造成索引的數(shù)據(jù)頁分裂。同時(shí)氓扛,更新索引上的值枯芬,可以理解為刪除一個(gè)舊的值,再插入一個(gè)新值采郎。這也會(huì)造成空洞的千所。也就是說,經(jīng)過大量增刪改的表蒜埋,都是可能是存在空洞的淫痰。所以,如果能夠把這些空洞去掉整份,就能達(dá)到收縮表空間的目的黑界。
三、收縮表空間的方法:
1皂林、重建表可以達(dá)到這樣的目的朗鸠。
2、重建表的方法:
??假設(shè)表A是需要收縮的表础倍,新建一個(gè)與表A結(jié)構(gòu)相同的表B烛占,然后按照主鍵ID遞增的順序,把數(shù)據(jù)一行一行地從表A里讀出來再插入到表B中沟启。由于表B是新建的表忆家,所以表A主鍵索引上的空洞,在表B中就都不存在了德迹。顯然地芽卿,表B的主鍵索引更緊湊,數(shù)據(jù)頁的利用率也更高胳搞。如果把表B作為臨時(shí)表卸例,數(shù)據(jù)從表A導(dǎo)入表B的操作完成后,用表B替換A肌毅,從效果上看筷转,就起到了收縮表A空間的作用。這里悬而,你可以使用alter table A engine=InnoDB命令來重建表呜舒。在MySQL 5.5版本之前,這個(gè)命令的執(zhí)行流程跟我們前面描述的差不多笨奠,區(qū)別只是這個(gè)臨時(shí)表B不需要你自己創(chuàng)建袭蝗,MySQL會(huì)自動(dòng)完成轉(zhuǎn)存數(shù)據(jù)唤殴、交換表名、刪除舊表的操作到腥。如果在這個(gè)過程中眨八,有新的數(shù)據(jù)要寫入到表A的話,就會(huì)造成數(shù)據(jù)丟失左电。因此廉侧,在整個(gè)DDL過程中,表A中不能有更新篓足。也就是說段誊,這個(gè)DDL不是Online的。
3栈拖、MySQL 5.6版本開始引入的Online DDL连舍,對(duì)上述的這個(gè)操作流程做了優(yōu)化。引入了Online DDL之后涩哟,重建表的流程:
?a索赏、建立一個(gè)臨時(shí)文件,掃描表A主鍵的所有數(shù)據(jù)頁贴彼;
?b潜腻、用數(shù)據(jù)頁中表A的記錄生成B+樹,存儲(chǔ)到臨時(shí)文件中器仗;
?c融涣、生成臨時(shí)文件的過程中,將所有對(duì)A的操作記錄在一個(gè)日志文件(row log)中精钮,對(duì)應(yīng)的是圖中state2的狀態(tài)威鹿;
?d、臨時(shí)文件生成后轨香,將日志文件中的操作應(yīng)用到臨時(shí)文件忽你,得到一個(gè)邏輯數(shù)據(jù)上與表A相同的數(shù)據(jù)文件,對(duì)應(yīng)的就是圖中state3的狀態(tài)臂容;
?e科雳、用臨時(shí)文件替換表A的數(shù)據(jù)文件。
由圖可以看出策橘,Online DDL和改鎖表DDL的區(qū)別是由于日志文件記錄和重放操作這個(gè)功能的存在炸渡,這個(gè)方案在重建表的過程中娜亿,允許對(duì)表A做增刪改操作丽已。
4、Online 和 inplace的區(qū)別:
??a买决、對(duì)于改鎖表DDL來說沛婴,我們把表A中的數(shù)據(jù)導(dǎo)出來的存放位置叫作tmp_table吼畏。這是一個(gè)臨時(shí)表,是在server層創(chuàng)建的嘁灯。而對(duì)于Online DDL泻蚊,根據(jù)表A重建出來的數(shù)據(jù)是放在“tmp_file”里的,這個(gè)臨時(shí)文件是InnoDB在內(nèi)部創(chuàng)建出來的丑婿。整個(gè)DDL過程都在InnoDB內(nèi)部完成性雄。對(duì)于server層來說,沒有把數(shù)據(jù)挪動(dòng)到臨時(shí)表羹奉,是一個(gè)“原地”操作秒旋,這就是“inplace”名稱的來源。(判斷相對(duì) Server 層沒有新建臨時(shí)表一種的方法:看命令執(zhí)行后影響的行數(shù)诀拭,沒有新建臨時(shí)表的話新建的行數(shù)是0迁筛。 )
?b、DDL過程如果是Online的耕挨,就一定是inplace的细卧;
?c、反過來則未必筒占,也就是說inplace的DDL贪庙,有可能不是Online的。比如說截止到MySQL 8.0中的添加全文索引(FULLTEXT index)和空間索引(SPATIAL index)就屬于這種情況翰苫。
5插勤、optimize table、analyze table和alter table這三種方式重建表的區(qū)別:
?a革骨、從MySQL 5.6版本開始农尖,alter table t engine = InnoDB(也就是recreate)默認(rèn)的就是上面Online DDL的流程了;
?b良哲、analyze table t 其實(shí)不是重建表盛卡,只是對(duì)表的索引信息做重新統(tǒng)計(jì),沒有修改數(shù)據(jù)筑凫,這個(gè)過程中加了MDL讀鎖滑沧;
?c、optimize table t 等于recreate+analyze巍实。
四滓技、收縮表空間,結(jié)果適得其反的原因:
?a棚潦、在重建表的時(shí)候令漂,InnoDB不會(huì)把整張表占滿,每個(gè)頁留了1/16給后續(xù)的更新用。也就是說叠必,其實(shí)重建表之后不是“最”緊湊的荚孵。假設(shè)此時(shí)的表本來就很緊湊,沒能整出多少剩余空間纬朝。重新收縮的過程中收叶,頁會(huì)按90%滿的比例來重新整理頁數(shù)據(jù)(10%留給UPDATE使用),未整理之前頁已經(jīng)占用90%以上共苛,收縮之后判没,文件就反而變大了。
?b隅茎、這個(gè)表哆致,本身就已經(jīng)沒有空洞的了,比如說剛剛做過一次重建表操作患膛。在DDL期間摊阀,如果剛好有外部的DML在執(zhí)行,這期間可能會(huì)引入一些新的空洞踪蹬。