ACID拉岁,是指在可靠數(shù)據(jù)庫管理系統(tǒng)(DBMS)中,事務(wù)(transaction)所應(yīng)該具有的四個(gè)特性:原子性(Atomicity)惰爬、一致性(Consistency)喊暖、隔離性(Isolation)、持久性(Durability).
事務(wù)日志僅僅是記錄與其對(duì)應(yīng)數(shù)據(jù)庫上的事務(wù)行為和對(duì)數(shù)據(jù)庫修改的日志文件(.ldf文件)
在SQL Server對(duì)于日志文件的管理撕瞧,是將邏輯上一個(gè)ldf文件劃分成多個(gè)邏輯上的虛擬日志文件(virtual log files,簡(jiǎn)稱VLFs).以便于管理陵叽。用個(gè)類比方法來看狞尔,日志文件(ldf)好比一趟火車,每一節(jié)車廂都是一個(gè)虛擬日志文件(VLFs):
因?yàn)镾QL Server通過這種方式使得存儲(chǔ)引擎管理事務(wù)日志更加有效.并且對(duì)于日志空間的重復(fù)利用也會(huì)更加高效巩掺。使用VLF作為收縮數(shù)據(jù)庫的最小單位比使用ldf文件作為最小單位無疑是更加高效的.
即使事務(wù)已經(jīng)到了Commit階段偏序,也僅僅只是把緩沖區(qū)(內(nèi)存中)的日志頁寫入日志(磁盤上),并沒有把數(shù)據(jù)寫入數(shù)據(jù)庫.那將要修改的數(shù)據(jù)頁寫入數(shù)據(jù)庫是在何時(shí)發(fā)生的呢?
1.完整(Full)備份:直接將所備份的數(shù)據(jù)的所有區(qū)(Extent)進(jìn)行復(fù)制胖替。這里值得注意的有2點(diǎn):
- 完整備份并不像其名字“完整”那樣備份所有部分研儒,而是僅備份數(shù)據(jù)庫本身,而不備份日志(雖然僅僅備份少量日志用于同步)
- 完整備份在備份期間独令,數(shù)據(jù)庫是可用的端朵。完整備份會(huì)記錄開始備份時(shí)的LSN號(hào),結(jié)束備份時(shí)的LSN號(hào)燃箭,以便在備份結(jié)束時(shí)將這期間的改動(dòng)應(yīng)用到備份冲呢,所以完整備份后數(shù)據(jù)的時(shí)間點(diǎn)是備份結(jié)束的時(shí)間。
2.差異(Differential)備份:只備份上次完整備份后招狸,做修改的部分敬拓。備份單位是區(qū)(Extent)。意味著某個(gè)區(qū)內(nèi)即使只有一頁做了變動(dòng)裙戏,則在差異備份里會(huì)被體現(xiàn).差異備份依靠一個(gè)BitMap進(jìn)行維護(hù)恩尾,一個(gè)Bit對(duì)應(yīng)一個(gè)區(qū),自上次完整備份后挽懦,被修改的區(qū)會(huì)被置為1翰意,而BitMap中被置為1對(duì)應(yīng)的區(qū)會(huì)被差異備份所備份。而到下一次完整備份后信柿,BitMap中所有的Bit都會(huì)被重置為0冀偶。
3.日志(Log)備份:僅僅備份自上次完整備份或日志備份之后的記錄。在簡(jiǎn)單模式下渔嚷,日志備份毫無意義(SQL Server不允許在簡(jiǎn)單恢復(fù)模式下備份日志)进鸠,下文會(huì)說明在簡(jiǎn)單恢復(fù)模式下,為什么日志備份沒有意義形病。
在簡(jiǎn)單恢復(fù)模式下客年,日志僅僅是為了保證SQL Server事務(wù)的ACID。并沒有恢復(fù)數(shù)據(jù)的功能
我們?cè)诿恐芤?點(diǎn)做一次完整備份漠吻,在周三0點(diǎn)和周五0點(diǎn)分別做差異備份量瓜。在簡(jiǎn)單恢復(fù)模式下,如果周六數(shù)據(jù)庫崩潰途乃。我們的恢復(fù)計(jì)劃只有根據(jù)周一0點(diǎn)的做的完整備份恢復(fù)后绍傲,再利用周五0點(diǎn)的差異備份進(jìn)行恢復(fù).而周五0點(diǎn)之后到服務(wù)器崩潰期間所有的數(shù)據(jù)將會(huì)丟失。
這就涉及到了一個(gè)概念—最小恢復(fù)LSN(Minimum Recovery LSN(MinLSN) )
MinLsn是在還未結(jié)束的事務(wù)記錄在日志中最小的LSN號(hào),MinLSN是下列三者之一的最小值:
- CheckPoint的開始LSN
- 還未結(jié)束的事務(wù)在日志的最小LSN
- 尚未傳遞給分發(fā)數(shù)據(jù)庫的最早的復(fù)制事務(wù)起點(diǎn)的 LSN.
可以看到,最新的LSN是148烫饼,147是CheckPoint,在這個(gè)CheckPoint之前事務(wù)1已經(jīng)完成猎塞,而事務(wù)2還未完成,所以對(duì)應(yīng)的MinLSN應(yīng)該是事務(wù)2的開始杠纵,也就是142.
而從MinLSN到日志的邏輯結(jié)尾處荠耽,則稱為活動(dòng)日志(Active Log)。
而活動(dòng)日志分布在物理VLF上的關(guān)系可以用下圖表示:
因此比藻,VLF的狀態(tài)是源自其上所含有的LSN的狀態(tài)骇塘,可以分為兩大類:活動(dòng)VLF和不活動(dòng)VLF
而更加細(xì)分可以將VLF的狀態(tài)分為以下四類:
- 活動(dòng)(Active) –在VLF 上存儲(chǔ)的任意一條LSN是活動(dòng)的時(shí),則VLF則為活動(dòng)狀態(tài)韩容,即使一個(gè)200M的VLF只包含了一條LSN,如上圖的VLF3
- 可恢復(fù)(Recoverable) – VLF是不活動(dòng)的唐瀑,VLF上不包含活動(dòng)LSN,但還未被截?cái)?truncated)
- 可重用(Reusable) – VLF是不活動(dòng)的群凶,VLF上不包含活動(dòng)LSN,已經(jīng)被截?cái)?truncated),可以重用
- 未使用(Unused) – VLF是不活動(dòng)的,并且還未被使用過
而所謂的截?cái)?truncated)只是將可恢復(fù)狀態(tài)的VLF轉(zhuǎn)換到可重用狀態(tài)哄辣。在簡(jiǎn)單恢復(fù)模式下请梢,每一次CheckPoint會(huì)引發(fā)一次截?cái)?而每一次CheckPoint都會(huì)將MinLSN向后推.所以當(dāng)事務(wù)結(jié)束后并且過了CheckPoint點(diǎn),其相關(guān)的日志將會(huì)被截?cái)嘁员阒貜?fù)利用空間力穗。
在日志達(dá)到日志文件(ldf文件)末尾時(shí)毅弧,也就是上圖的VLF8時(shí),會(huì)重新循環(huán)到VLF1開始当窗,以便讓空間進(jìn)行重復(fù)利用.所以日志雖然可以從物理順序上是從VLF1到VLF8够坐,但邏輯順序可以是從VLF6開始到VLF2結(jié)束:
因此可以看出,簡(jiǎn)單恢復(fù)模式下日志是不保存的(當(dāng)事務(wù)結(jié)束后崖面,相關(guān)的會(huì)被截?cái)啵┰H僅是用于保證事務(wù)回滾和崩潰恢復(fù)的用途.所以備份日志也就無從談起,更不能利用日志來恢復(fù)數(shù)據(jù)庫巫员。
在完整恢復(fù)模式下庶香,CheckPoint不會(huì)截?cái)嗳罩尽V挥袑?duì)日志的備份才會(huì)將MinLSN向后推并截?cái)嗳罩炯蚴丁R虼嗽谝粋€(gè)業(yè)務(wù)量稍大的系統(tǒng)中赶掖,日志的增長(zhǎng)速度將會(huì)變得很快。
在DB_1處做了完整備份七扰,并且接下來兩次分別做了兩次日志備份(Log_1和Log_2),在Log_2備份完不久服務(wù)器由于數(shù)據(jù)所在磁盤損壞奢赂。這時(shí)如果日志文件完好,則可以通過備份尾部日志(Tail of log)后颈走,從DB_1開始恢復(fù)呈驶,依次恢復(fù)Log_1,Log_2,尾部日志來將數(shù)據(jù)庫恢復(fù)到災(zāi)難發(fā)生時(shí)的時(shí)間點(diǎn)。理論上可以使數(shù)據(jù)的損失為0疫鹊。
從日志恢復(fù)數(shù)據(jù)的原理是Redo,也就是將日志中記載的事務(wù)再重做一遍袖瞻。這個(gè)開銷和從完整或差異備份中恢復(fù)相比司致,要大很多。因此盡可能的減少利用日志的恢復(fù)量聋迎。而使用完整或者差異備份來恢復(fù)更多的數(shù)據(jù)脂矫。
大容量恢復(fù)模式在很多地方和完整恢復(fù)模式相同。但由于在完整恢復(fù)模式下霉晕,對(duì)數(shù)據(jù)庫的每一項(xiàng)操作都會(huì)記錄在日志中庭再。而對(duì)于某些大量數(shù)據(jù)的導(dǎo)入導(dǎo)出操作,無疑會(huì)在日志中留下大量記錄牺堰。很多情況下拄轻,我們并不需要將這些信息記錄在日志中。
連續(xù)的日志備份被稱之為日志鏈伟葫。表示日志是連續(xù)的.這個(gè)概念可以用下圖表示:
1.復(fù)制數(shù)據(jù)階段:從完整備份和差異備份中將數(shù)據(jù)恨搓,索引頁和日志復(fù)制到被恢復(fù)數(shù)據(jù)庫文件。
2.Redo(roll forward)階段:將記錄在日志中的事務(wù)應(yīng)用到從備份中復(fù)制過來的數(shù)據(jù)筏养。使數(shù)據(jù)Roll Forward到指定的時(shí)間點(diǎn).這個(gè)階段完成后斧抱,數(shù)據(jù)庫還處于不可使用階段:
上面兩部就是Restore
3.Undo(Roll Back)階段:這也是傳說中的Recovery,將任何未提交的事務(wù)回滾渐溶。這個(gè)階段過后辉浦,數(shù)據(jù)庫處于可用狀態(tài)。任何后續(xù)備份將不能接著應(yīng)用到當(dāng)前數(shù)據(jù)庫茎辐。
在連續(xù)兩個(gè)日志鏈的日志備份宪郊,在第一個(gè)事務(wù)日志備份中定義的事務(wù),在第二個(gè)事務(wù)日志備份中Commit.如果在第一個(gè)事務(wù)日志還原后使用了Recovery選項(xiàng).也就是經(jīng)歷了Undo階段拖陆。則事務(wù)1在Undo階段會(huì)被回滾:
可見废膘,日志備份1中的T1被回滾,在日志備份2中的Commit也就毫無意義慕蔚。這也就是為什么經(jīng)歷過Undo階段后不允許再恢復(fù)后續(xù)備份丐黄。因此,微軟推薦的最佳實(shí)踐是使用NoRecovery選項(xiàng)不進(jìn)行Undo階段孔飒。而在所有備份恢復(fù)后單獨(dú)進(jìn)行Undo階段,這個(gè)操作可以通過還原日志尾部時(shí)桂对,指定Recovery選項(xiàng)進(jìn)行。
前面說過鸠匀,日志文件中的LSN號(hào)是可以比較的,如果LSN2>LSN1,則說明LSN2的發(fā)生時(shí)間晚于LSN1的發(fā)生時(shí)間宅此。CheckPoint或Lazy Writer通過將日志文件末尾的LSN號(hào)和緩沖區(qū)中數(shù)據(jù)文件的LSN進(jìn)行對(duì)比弱匪,只有緩沖區(qū)內(nèi)LSN號(hào)小于日志文件末尾的LSN號(hào)的數(shù)據(jù)(注意這里寫的是數(shù)據(jù)頁,而不在是日志帘饶,即上圖的橢圓形區(qū)域步驟)才會(huì)被寫入到磁盤中的數(shù)據(jù)庫。因此確保了WAL(在數(shù)據(jù)寫入到數(shù)據(jù)庫之前,先寫入日志)。