SQL Server事務(wù)日志-檢查點、redo和undo(1)

日志記錄

使用最為廣泛的記錄數(shù)據(jù)庫修改的結(jié)構(gòu)就是日志。日志是日志記錄的序列,它記錄數(shù)據(jù)庫中的所有更新活動。
??日志記錄有幾種,更新日志記錄(update log record)描述一次數(shù)據(jù)庫寫操作,它具有如下幾個字段:

  • 事務(wù)標識:執(zhí)行write操作的事務(wù)的唯一標識
  • 數(shù)據(jù)項標識:是所寫數(shù)據(jù)項的唯一標識。通常是數(shù)據(jù)項在磁盤上的位置,包括數(shù)據(jù)項所駐留的塊的塊標識和塊內(nèi)偏移量
  • 舊值:數(shù)據(jù)項的寫前值
  • 新值:數(shù)據(jù)項的寫后值

我們將一個更新日志記錄表示為<Ti,Xj,V1,V2>,表明事務(wù)Ti對數(shù)據(jù)項Xj執(zhí)行了一個寫操作,寫操作前Xj的值時V1,寫操作后Xj的值是V2。其他專門的日志記錄用于記錄事務(wù)處理過程中的重要事件,如事務(wù)的開始以及事務(wù)的提交或中止。如下是一些日志記錄類型:

  • <Ti start>:事務(wù)Ti開始
  • <Ti commit>:事務(wù)Ti提交
  • <Ti abort>:事務(wù)Ti中止

后面將介紹幾種其他的日志記錄類型。
??每次事務(wù)執(zhí)行寫操作時,必須在數(shù)據(jù)庫修改前建立建立該次寫操作的日志記錄并把它加入到日志中。一旦日志記錄已存在,就可以根據(jù)需要將修改輸出到數(shù)據(jù)庫中。并且,我們有能力撤銷已經(jīng)輸出到數(shù)據(jù)庫中的修改,這是利用日志記錄中的舊值字段來做的。
??為了從系統(tǒng)故障和磁盤故障中恢復(fù)時能使用日志記錄,日志必須存放在穩(wěn)定存儲器中。

數(shù)據(jù)庫修改

事務(wù)在進行數(shù)據(jù)項修改中所采取的步驟:
??1.事務(wù)在主存中自己私有的部分執(zhí)行某些計算。
??2.事務(wù)修改主存的磁盤緩沖區(qū)中包含該數(shù)據(jù)項的數(shù)據(jù)塊。
??3.數(shù)據(jù)庫系統(tǒng)執(zhí)行output操作,將數(shù)據(jù)塊寫入磁盤中。

如果一個事務(wù)執(zhí)行了對磁盤緩沖區(qū)或磁盤自身的更新,我們說這個事務(wù)修改了數(shù)據(jù)庫;而對事務(wù)在主存中自己私有的部分進行的更新不算數(shù)據(jù)庫修改。如果一個事務(wù)直到它提交時都沒有修改數(shù)據(jù)庫,我們就說它采用了延遲修改技術(shù)。如果數(shù)據(jù)庫修改在事務(wù)仍然活躍時發(fā)生,我們就說它采用了立即修改技術(shù)。

恢復(fù)算法必須考慮多種因素,包括:

  • 有可能一個事務(wù)已經(jīng)提交了,雖然它所做的某些數(shù)據(jù)庫修改還僅僅存在于主存的磁盤緩沖區(qū)中,而不再磁盤的數(shù)據(jù)庫中。
  • 有可能處于活動狀態(tài)的一個事務(wù)已經(jīng)修改了數(shù)據(jù)庫,而作為后來發(fā)生的故障的結(jié)果,這個事務(wù)需要終止。

由于所有的數(shù)據(jù)庫修改之前必須建立日志記錄,因此系統(tǒng)有數(shù)據(jù)庫修改前的舊值和要寫給數(shù)據(jù)項的新值可以用。這就使得系統(tǒng)能執(zhí)行適當?shù)膗ndo和redo操作。

  • undo使用一個日志記錄,將該日志記錄中指明的數(shù)據(jù)項設(shè)置為舊值
  • redo使用一個日志記錄,將該日志記錄中指明的數(shù)據(jù)項設(shè)置為新值

檢查點和日志的活動部分

當系統(tǒng)故障發(fā)生時,我們必須檢查日志,決定哪些事務(wù)需要重做,哪些需要撤銷。原則上,我們需要搜索整個日志來確定該信息。這樣做有兩個主要的困難:

  • 搜索過程太耗時
  • 根據(jù)我們的算法,大多數(shù)需要重做的事務(wù)已經(jīng)把其更新寫入數(shù)據(jù)庫。盡管對它們重做不會造成不良后果,但會使恢復(fù)過程變得更長。

為了降低這種開銷,引入檢查點。

檢查點操作
SQL Server 生成檢查點的過程如下:

  • ①將標記檢查點起點的日志記錄寫入日志文件。(日志記錄≠日志文件)

  • ②將為檢查點記錄的信息存儲在檢查點日志記錄鏈中。
    ??檢查點中記錄的一條信息是“最小恢復(fù) LSN”(“MinLSN”),它是成功進行數(shù)據(jù)庫范圍內(nèi)回滾所需的最早日志記錄的日志序列號。MinLSN 是下列各項中的最小者:

  • 檢查點起點的 LSN。

  • 最早的活動事務(wù)起點的 LSN。

  • 尚未傳遞給分發(fā)數(shù)據(jù)庫的最早的復(fù)制事務(wù)起點的 LSN。

  • ③在檢查點記錄中記錄所有的未完成的活動事務(wù)。

  • ④如果數(shù)據(jù)庫工作在【簡單恢復(fù)模式】,刪除新的MinLSN之前的所有日志記錄(日志截斷)。

  • ⑤將當前位于主存的所有日志記錄輸出到穩(wěn)定存儲區(qū)。

  • ⑥將所有修改后的緩沖塊寫入磁盤。

  • ⑦將標記檢查點記錄結(jié)束的記錄寫入日志文件。

  • ⑧將檢查點日志記錄鏈<checkpoint L>輸出到穩(wěn)定存儲器,其中L是執(zhí)行檢查點時正活躍的事務(wù)的列表。

在檢查點執(zhí)行過程中,不允許事務(wù)執(zhí)行任何更新動作,如往緩沖塊中寫入或?qū)懭罩居涗洝?br> ??在上面的過程中,我們在日志中加入了<checkpoint L>記錄使得系統(tǒng)提高恢復(fù)過程的效率??紤]在檢查點前完成的事務(wù)Ti。對于這樣的事務(wù),<Ti commit>記錄(或<Ti abort>記錄)在日志中出現(xiàn)在<checkpoint>記錄之前。Ti所做的任何數(shù)據(jù)庫修改都必然已在檢查點前或作為檢查點本身的一部分寫入數(shù)據(jù)庫。因此,在恢復(fù)時就不必再對Ti執(zhí)行redo操作了。
??在系統(tǒng)崩潰發(fā)生之后,系統(tǒng)檢查日志以找到最后一條<checkpoint L>記錄(這可以通過從尾端開始反向搜索日志來進行,直到遇到第一條<checkpoint L>記錄)
??只需要對L中的事務(wù),以及<checkpoint L>記錄寫到日志中之后才執(zhí)行的事務(wù)進行undo或redo操作。讓我們把這個事務(wù)集合記為T。

  • 對T中所有事務(wù)Tk,若日志中既沒有<Tk commit>記錄,也沒有<Tk abort>記錄,則執(zhí)行undo(Tk)。
  • 對T中所有事務(wù)Tk,若日志中有<Tk commit>記錄或<Tk abort>記錄,則執(zhí)行redo(Tk)。

請注意,要找出事務(wù)集合T,和確定T中的每個事務(wù)是否有commit或abort記錄出現(xiàn)在日志中,我們只需要檢查日志中從最后一條checkpoint日志記錄開始的部分。

MinLSN的選擇
??MinLSN實際上代表了數(shù)據(jù)庫從檢查點恢復(fù)時,具體從哪個LSN號開始掃描并進行恢復(fù)。所以MinLSN的選擇是檢查點時的LSN和最早的活動事務(wù)起點LSN兩者比較的最小值。
??如圖,事務(wù)2為檢查點時的唯一活動事務(wù),其起點的LSN1小于檢查點發(fā)生時的LSN2,所以MinLSN取LSN1就可以。

檢查點與恢復(fù)效率的關(guān)系
??檢查點將臟數(shù)據(jù)頁從當前數(shù)據(jù)庫的緩沖區(qū)高速緩存刷新到磁盤上。 這最大限度地減少了恢復(fù)時必須重做(Redo)的修改量。
??為什么在日志文件中設(shè)置了檢查點之后,基于日志的恢復(fù)機制就可以提高效率了呢?如圖所示為檢查點發(fā)生時可能的事務(wù)的狀態(tài)。


① 事務(wù)1
其start和commit日志記錄都發(fā)生在檢查點之前,這樣的事務(wù)其結(jié)果已經(jīng)反映到物理介質(zhì)上去了(因為檢查點會保證WAL協(xié)議,確保數(shù)據(jù)被寫入),所以在恢復(fù)時無須對該事務(wù)做Redo操作。
② 事務(wù)2
其start日志記錄在檢查點之前發(fā)生,其commit記錄在故障點之前發(fā)生,說明日志中事務(wù)已經(jīng)完美提交,但數(shù)據(jù)不一定已經(jīng)寫入,所以屬于圓滿事務(wù),需要Redo操作。
③ 事務(wù)3
其start日志記錄在檢查點之后發(fā)生,其commit記錄在故障點之前發(fā)生,說明日志中事務(wù)已經(jīng)完美提交,但數(shù)據(jù)不一定已經(jīng)寫入,所以屬于圓滿事務(wù),需要Redo操作。
④ 事務(wù)4
其start日志記錄在檢查點之后發(fā)生,其commit記錄在故障點之前尚未發(fā)生,說明日志中事務(wù)為中止事務(wù),需要Undo操作。
⑤ 事務(wù)5
其start日志記錄在檢查點之前發(fā)生,其commit記錄在故障點之前尚未發(fā)生,說明日志中事務(wù)為中止事務(wù),需要Undo操作。

由CheckPoint的機制可以看出,由于內(nèi)存中的數(shù)據(jù)往往比持久化存儲中的數(shù)據(jù)更新,而CheckPoint保證了這部分數(shù)據(jù)能夠被持久化到磁盤,因此CheckPoint之前的數(shù)據(jù)一定不會再需要被Redo。

自動檢查點
?? SQL Server 會自動產(chǎn)生檢查點事件,它在后臺有一條線程負責產(chǎn)生與執(zhí)行檢查點事件。 自動檢查點之間的間隔基于使用的日志空間量以及自上一個檢查點以來經(jīng)歷的時間。 如果只在數(shù)據(jù)庫中進行了很少的修改,自動檢查點之間的時間間隔可能變化很大并且很長。 如果修改了大量數(shù)據(jù),自動檢查點也會經(jīng)常出現(xiàn)。
??自動檢查點之間的間隔是以“恢復(fù)間隔”配置算出的。此選項指定數(shù)據(jù)庫引擎在系統(tǒng)重新啟動時恢復(fù)數(shù)據(jù)庫所用的最長時間。 數(shù)據(jù)庫引擎將估計在執(zhí)行恢復(fù)操作期間自己在“恢復(fù)間隔”內(nèi)能夠處理多少條日志記錄。
??自動檢查點之間的間隔也取決于恢復(fù)模式:

  • 如果數(shù)據(jù)庫使用的是完整恢復(fù)模式或批量日志恢復(fù)模式,則每當日志記錄數(shù)達到數(shù)據(jù)庫引擎估計在“恢復(fù)間隔”選項中指定的時間內(nèi)可以處理的數(shù)量時,便會生成一個自動檢查點。
  • 如果數(shù)據(jù)庫使用的是簡單恢復(fù)模式,只要日志記錄數(shù)達到下面兩個值中較小的那個值,就會生成自動檢查點:
  • 日志已滿 70%。
  • 日志記錄數(shù)達到數(shù)據(jù)庫引擎估計在“恢復(fù)間隔”選項指定的時間內(nèi)能夠處理的記錄數(shù)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容