在數(shù)據(jù)庫運行時,出現(xiàn)宕機、停電、系統(tǒng)崩潰等異常情況,造成內(nèi)存和表空間文件在交換過程中,因為出現(xiàn)問題造成頁出錯,形成表空間文件的頁損壞或者丟失等情況,使表空間的文件無法正常使用。表空間和緩存是InnoDB引擎的主要組成部分,兩者之間的交互是很頻繁的。這種交互之所以可以實現(xiàn),依靠的是InnoDB Master線程。InnoDB的主要工作都是在一個或者多個單獨的Master線程中完成的,Master線程的優(yōu)先級最高,分為主循環(huán)、后臺循環(huán)、刷新循環(huán)、暫停循環(huán)等循環(huán),最主要的是主循環(huán)。主循環(huán)每秒執(zhí)行一次刷新日志緩沖區(qū),合并插入緩沖,最多刷新100個臟數(shù)據(jù)頁,如果當(dāng)前用戶沒有活動信息,切換到后臺循環(huán)等操作。
刷新日志緩沖是必須要做的,將日志緩存中的數(shù)據(jù)寫入到磁盤文件,指的是Redo日志和Undo日志,前者用于重做緩存,后者用來執(zhí)行撤銷操作。在一個事物中經(jīng)過一番數(shù)據(jù)操作后,希望執(zhí)行RollBack回滾來撤銷操作,就必須用到Undo日志。其余的操作不一定必須發(fā)生。插入緩存是針對索引而言的,當(dāng)向數(shù)據(jù)表中插入數(shù)據(jù)時,必然涉及對索引修改,當(dāng)對數(shù)據(jù)表進行頻繁修改時,InnoDB會將關(guān)于索引的改變信息暫時寫入InnoDB Buffer Pool中的插入緩存中,之后將其合并寫入真正的索引文件中。這樣,可以優(yōu)化索引的效率,讓索引中的數(shù)據(jù)盡可能地進行序列化存儲。
實際上,InnoDB Buffer Pool和表空間文件的交互是很頻繁的,表空間文件中存儲了各種數(shù)據(jù),例如數(shù)據(jù)、索引等,都會被從磁盤中的存儲文件中抽取出來,放入InnoDB Buffer Pool中緩存起來。如果出現(xiàn)服務(wù)器宕機、停電等情況,就會造成內(nèi)存中的這些動態(tài)數(shù)據(jù)的丟失,無法寫入到表空間文件。如果這種損壞超出了InnoDB引擎可以自動修復(fù)的范圍,例如,當(dāng)緩存中的Redo日志寫入到“ib_logfile”日志文件時出錯,造成日志文件損壞,那么InnoDB就無法對數(shù)據(jù)進行恢復(fù),自然無法修復(fù)損壞的數(shù)據(jù)表。所謂臟數(shù)據(jù)頁,指的是在緩存中存儲的對數(shù)據(jù)的改變,寫回磁盤稱為刷新臟數(shù)據(jù)頁。Master線程每10秒執(zhí)行一次合并最多5個插入緩沖,刷新日志緩沖,刷新10或100個臟頁到磁盤,產(chǎn)生一個檢查點,刪除無用的Undo也等操作,這些操作必須發(fā)生。當(dāng)沒有用戶活動或關(guān)閉數(shù)據(jù)庫的情況下,才會執(zhí)行后臺循環(huán),操作包括刪除無用的Undo頁、合并20個插入緩沖、跳回主循環(huán)、不斷刷新100個頁,直到符合條件跳轉(zhuǎn)到刷新循環(huán)。
綜上所述可以看出,InnoDB引擎的內(nèi)存緩沖和磁盤中的文件是連續(xù)不斷互動的。在這些環(huán)節(jié)中,有可能在多個地方發(fā)生錯誤,例如,在InnoDB Buffer Pool中Data page部分在讀寫過程中,如果一些臟頁(即發(fā)生改變的數(shù)據(jù))沒有及時寫回磁盤,就容易導(dǎo)致錯誤的發(fā)生。當(dāng)然,如果存在Redo Log日志,就有補救的機會。當(dāng)Insert Buffer中的數(shù)據(jù)寫回到表空間文件的索引部分中時,如果發(fā)生異常,就可能導(dǎo)致索引的結(jié)構(gòu)出現(xiàn)損壞。當(dāng)Redo Log日志寫入磁盤時,也有可能發(fā)生問題,導(dǎo)致表空間文件損壞。