1. 程式人生 > >再談SQL Server中日誌的的作用

再談SQL Server中日誌的的作用

簡介

    之前我已經寫了一個關於SQL Server日誌的簡單系列文章。本篇文章會進一步挖掘日誌背後的一些概念,原理以及作用。如果您沒有看過我之前的文章,請參閱:

資料庫的可靠性

    在關係資料庫系統中,我們需要資料庫可靠,所謂的可靠就是當遇見如下兩種情況之一時保證資料庫的一致性:

  • 在系統崩潰/故障等情況下,保證資料庫的一致性
  • 資料不能在多個DML語句同時修改資料的情況下,導致不一致或資料損壞

    實際上,上述第二種情況就是併發性所需要解決的問題,傳統關係資料庫中,我們用鎖來解決這個問題,而對於記憶體資料庫或帶有樂觀併發控制的資料庫系統,通過多版本併發控制(MVCC)來解決這個問題。因為本篇文章的主旨是討論日誌而不是併發,因此對於上述第二種情況不會詳細解釋。

    我們上面還多次提到了一致性(Consistence),在開始瞭解日誌如何維持一致性之前,我們首先要明白什麼是一致性。一致性在資料庫系統中所指的內容比較廣,一致性不僅僅需要資料庫中的資料滿足各種約束,比如說唯一約束,主鍵約束等,還需要滿足資料庫設計者心中的隱式約束,簡單的業務約束比如說性別這列只允許男或女,這類隱式約束通常使用觸發器或約束來實現,或是在資料庫所服務的應用程式中進行約束。

    下面我們把一致性的範圍縮減到事務一致性,事務一致性的概念學術上的解釋為:

如果事務執行期間沒有出現系統錯誤或其他事務錯誤,並且資料庫在事務開始期間是資料一致的,那麼在該事務結束時,我們認為資料庫仍然保證了一致性。

    因此,引申出來事務必須滿足原子性,也就是事務不允許部分執行。事務的部分執行等同於將資料庫置於不一致的境地之下。此外多事務併發執行也可能導致資料庫不一致,除非資料庫系統對併發進行控制。

    關於上面的顯式約束,由資料庫系統來實現,比如說違反了一致性約束的語句會導致資料庫系統報錯並拒絕執行。但一些隱式的事務約束,比如說寫語句的開發人員對系統設計者所設計的規則並不瞭解,導致了違反業務規則的資料修改,這種情況在資料庫端很難探查。但是這種問題通常可以規則到許可權控制的領域,我們認為授予某個使用者修改特定資料的許可權,就認為這個使用者應該瞭解資料庫中隱式和顯式的規則。

    除去這些業務上的資料不一致之外,我們需要在系統崩潰等情況下保證資料的一致性,而可能導致這類資料不一致的情況包括但不限於下面這些情況:

  •     儲存系統損壞,比如說磁碟上位元組級別的損壞,這類問題通常可以通過磁碟上的奇偶校驗發現,另外還有一些大一些的問題,比如說整個儲存系統崩潰。這類問題的修復手段取決於前期工作,比如說備份策略,高可用性架構,SAN Replication等技術。
  •     機房整體損壞,這類問題比較極端,只有異地機房容災可以解決。
  •     系統故障,修改資料的程序都需要事務作為上下文,和其他概念一樣,事務也是有狀態的。而事務狀態通常儲存在易丟失的主存中,因此,當出現系統故障、程序崩潰等系統失敗時,可能導致事務狀態的丟失,此時,我們就無法得知事務中的哪部分已經執行而哪部分還未執行,重新執行事務並不會解決這類問題,因為有可能導致事務中某部分的重複執行。因此解決這類問題的方式就是將事務的狀態以及對資料庫修改的詳細步驟與記憶體中的資料分開存放,並存儲於磁碟等穩定的介質中,當系統故障等情況下,我們可以通過這些記錄來將系統恢復到一致性的狀態之下,我們對這類儲存,稱之為日誌。

SQLServer中的日誌

    SQL Server中靠日誌來維護一致性(當然,日誌的作用非常多,但一致性是日誌的基本功能,其他功能可以看作是額外的功能)。通常我們建立資料庫的時候,會附帶一個副檔名為ldf的日誌檔案。日誌檔案其實本質上就是日誌記錄的集合。在SQL Server中,我們可以通過DBCC LOGINFO來看這個日誌的資訊,如圖1所示。

    1

    圖1.DBCC LOGINFO

    該命令可以從VLF的角度從一個比較高的層級看日誌。其中值得注意的列是VLF大小,狀態(2表示使用,0表示從未使用過),偏移量。對於這些資訊對我們規劃VLF數量的時候很有幫助,因為VLF過多可能引起嚴重的效能問題,尤其是在複製等Scale-Out或HA環境下。

    然後,事務對資料庫中每次修改都會分解成多個多個原子層級的條目被記錄到持久儲存中,這些條目就是所謂的日誌記錄(Log Record),我們可以通過fn_dblog來檢視這些條目。如圖2所示。

2

圖2.Fn_dblog

    每個日誌記錄都會被背賦予一個唯一的順序編號,這個編號大小為10位元組,由三部分組成,分別為:

  •     VLF順序號(4位元組)
  •     Log Block順序號(4位元組)
  •     Log Block內的順序編號(2位元組)

    因此,由於VLF是不斷遞增的(同一個VLF被複用會導致編號改變),因此LSN序號也是不斷遞增的。因此,通過上面的LSN結構不難發現,如果比VLF更小的粒度並不是直接對應LOG RECORD,而是LOG Block。Log Block是日誌寫入持久化儲存的最小單位,Log Block的大小從512位元組到60K不等,這取決於事務的大小,那些在記憶體還未被寫入持久化儲存的Log Block也就是所謂的In-Flight日誌。以下兩個因素決定Log Block的大小:

  • 事務提交或回滾
  • Log Block滿60K會強制Flush到持久化儲存,以保證WAL

    因此當一個事務很大時(比如說大面積update),每60K就會成為一個Log Block寫入持久化儲存。而對於很多小事務,提交或回滾就會稱為一個Block寫入持久化儲存,因此根據事務的大小,LOG Block的大小也會不同。值得疑惑的是,因為磁碟上分配單元的大小是2的N次方,因此最接近LOG BLOCK的大小應該是64K,而SQL Server為什麼不把Log Block設定為64K呢。這樣可以更優化IO。

    VLF和Log Block和Log Record的關係如圖3所示。

    3

    圖3.三者之間的關係

    從比較高的層級瞭解了日誌之後,我們再仔細瞭解日誌中應該儲存的關鍵資訊,每條Log Record中都包含下面一部分關鍵資訊:

  • LSN
  • Log Record的Context
  • Log Record所屬的事務ID(所有的使用者事務都會存在事務ID)
  • Log Record所佔的位元組
  • 同一個事務中上一條Log Record的LSN(用於Undo)
  • 為Undo所保留的日誌空間

    當然,這些僅僅是日誌的一小部分內容。通過Log Record所記錄的內容,就能夠精確的記錄對資料庫所做的修改。

日誌用於Undo

    在瞭解為了Undo,日誌所起的作用之前,我們首先可以瞭解一下為什麼需要事務存在回滾:

  • 因為事務可能失敗,或者死鎖等原因,如果希望事務不違反原子性而造成資料庫不一致的話,則需要通過回滾將已經部分執行的事務回滾掉。
  • 根據業務需求,如果在某些關聯業務失敗等情況下,回滾資料。

    因此,Log Record會為這些列儲存一些位元組來執行資料庫回滾,最簡單的例子莫過於執行插入後Rollback事務,則日誌會產生一條所謂的Compensation Log Record來反操作前面已經插入的事務,如圖4所示。

    4

    圖4.Compensation Log示例

    圖4執行的是一個簡單的Insert語句,然後回滾。我們看到,SQL Server生成了一個Compensation Log Record來執行反向操作,也就是Delete操作。值得注意的是,為了防止這些回滾操作,SQL Server會保留一些空間用於執行回滾,我們看到LOP_INSERT_ROWS保留的74位元組空間被下面的Compensation Log Record所消耗。Compensation Log record還有一個指向之前LSN的列,用於回滾,直至找到LOP_BEGIN_XACT的事務開始標記。另外,Compenstion Log Record只能夠用於Redo,而不能用於Undo。

    那假設我們某一個事務中刪除了多條資料怎麼辦?比如說,某一個事務中一個Delete語句刪除了10行,則需要在Log Record對應10個LOP_DELETE_ROWS(引申一下,由此我們可以看出某一個語句可能導致N個Log Record,這麼多Log Record在複製,映象時都需要在另一端Redo,因此需要額外的開銷),如果我們此時RollBack了該事務,則Redo的順序是什麼呢,如圖5所示。

    5

    圖5.回滾事務

    圖5中,刪除3條資料後,進行回滾,首先從刪除3開始,生成對應的反向Compensation Log Record,並指向刪除2,再對應刪除2生成反向Compensation Log Record並指向刪除1,以此類推,最終回滾事務指回開始事務。

日誌用於Redo

    與Undo不同,在計算機儲存體系中,輔助儲存通常是帶有磁頭的磁碟。這類儲存系統的IOPS非常低,因此如果對於事務對資料庫執行的修改操作,我們積累到一定量再寫入磁碟,無疑會提高IO的利用率。但是在資料在主存還沒有持久化的輔助儲存的期間,如果遭遇系統故障,則這部分資料的丟失則可能導致資料庫的不一致狀態。

   因此,使用日誌使得該問題得到解決。與日誌Undo方面的不同之處在於:Undo用於解決事務未完成和事務回滾的情況,而Redo則是為了保證已經提交的事務所做的修改持久化到輔助儲存。

   Redo則引申出了WAL,即事務日誌會在COMMIT或COMMIT之前寫入持久化儲存中,然後事務對資料本身的修改才能生效。因此就能夠保證在系統故障時可以通過讀取日誌來Redo日誌的持久化操作。因此對於終端使用者可以顯示事務已經提交而暫時不用將所修改的資料寫入持久化儲存。由於資料在日誌未寫入持久化儲存之前無法持久化,則需要更大的主存作為BUFFER空間。

    因為日誌既要用於Undo,又要用於Redo,因此為了能夠成功生成Compensation Log Record,需要日誌既記錄被修改前的資料,又記錄被修改後的資料,比如我們在圖6中做一個簡單的更新。

6

圖6.記錄更新之前和之後的資料

   值得注意的是,如果修改的值是聚集索引鍵,則由於修改該資料會導致儲存的物理位置改變,所以SQL Server並不會像這樣做即席更新,而是刪除資料再插入資料,從而導致成本的增加,因此儘量不要修改聚集索引鍵。

Undo/Redo Recovery

    當SQL Server非正常原因關閉時,也就是在沒有走CheckPoint(會在下面提到)時關閉了資料庫,此時資料庫中資料本身可能存在不一致的問題。因此在資料庫再次啟動的時候,會去掃描日誌,找出那些未提交卻寫入持久化儲存的資料,或已提交卻未寫入持久化儲存的資料,來進行Undo和Redo來保證事務的一致性。Undo/Redo Recovery遵循以下規則:

  • 按照由早到晚的順序Redo該已提交卻未寫入持久化儲存的資料
  • 按照由晚到早的順序Undo未提交,卻寫入持久化儲存的資料

    圖7中,我們進行一個簡單測試,在啟動過程中,首先禁用了CheckPoint以防止自動CheckPoint,然後我們修改資料,不提交,並持久化到磁碟。另一個執行緒修改資料並提交,但未持久化到磁碟。為了簡單起見,我把兩個執行緒寫到一個視窗中。

    7

    圖7.需要Undo和Redo的兩個事務

    此時我們強制殺死SQL Server程序,導致資料本身不一致,此時在SQL Server的重啟過程中,會自動的Redo和Undo上面的日誌,如圖8所示。

8

    圖8.實現Redo和Undo

那麼,什麼是CheckPoint?

    圖8給出的簡單例子足以說明Recovery機制。但例子過於簡單,假如一個非常繁忙的資料庫可能存在大量日誌,一個日誌如果全部需要在Recovery過程中被掃描的話,那麼Recovery過程所導致的宕機時間將會成為噩夢。因此,我們引入一個叫CheckPoint的機制,就像其名稱那樣,CheckPoint就是一個存檔點,意味著我們可以從該點繼續開始。

    在Undo/Redo機制的資料庫系統中,CheckPoint的機制如下:

1.將CheckPoint標記寫入日誌(標記中包含當前資料庫中活動的事務資訊),並將Log Block寫入持久化儲存

2.將Buffer Pool中所有的髒頁寫入磁碟,所有的髒頁包含了未提交事務所修改的資料

3.將結束CKPT標記寫入日誌,並將Log Block寫入持久化儲存

    我們在日誌中可以看到的CheckPoint標記如圖9所示。

    9

圖9.CheckPoint標記

   其中,這些Log Record會包含CheckPoint的開始時間,結束時間以及MinLSN,用於複製的LSN等。由圖9中我們還可以看到一個LOP_XACT_CKPT操作的Log Record,該操作符的上下文如果為NULL的話,則意味著當前:

  • 包含未提交事務
  • 該Log Record記錄包含未提交事務的個數
  • 包含未提交的事務所涉及的LSN

   由CheckPoint的機制可以看出,由於記憶體中的資料往往比持久化儲存中的資料更新,而CheckPoint保證了這部分資料能夠被持久化到磁碟,因此CheckPoint之前的資料一定不會再需要被Redo。而對於未提交的事物所修改的資料寫入持久化儲存,則可以通過Undo來回滾事務(未提交的事物會導致CheckPoint無法截斷日誌,因此這部分日誌可以在Recovery的時候被讀取到,即使這部分日誌在CheckPoint之前)。

此時,我們就可以100%的保證,CheckPoint之前的日誌就可以被安全刪除(簡單恢復模式)或歸檔了(完整恢復模式),在Recovery時,僅僅需要從CheckPoint開始掃描日誌,從而減少宕機時間。

小結

    本篇文章深入挖掘了資料庫中日誌為保護資料一致性的的作用、實現原理。日誌在這些功能之外,也是為了用於實現高可用性,因此瞭解這些原理,可以更好的幫助我們在搭建高可用性拓撲以及設計備份計劃時避免一些誤區。

相關推薦

SQL Server日誌的的作用

簡介     之前我已經寫了一個關於SQL Server日誌的簡單系列文章。本篇文章會進一步挖掘日誌背後的一些概念,原理以及作用。如果您沒有看過我之前的文章,請參閱: 資料庫的可靠性     在關係資料庫系統中,我們需要資料庫可靠,所謂的可靠就是當遇見如下兩種情況之一時保證資料庫

SQL Server字串拆分與表格分列

字串拆分函式 剛工作那會寫了一篇關於字串拆分的文章,那時僅僅是考慮實現就可以了,沒考慮效能、簡潔等因素,現總結一下常用方法以及優劣。 為了考慮程式碼的可讀性和複用性,一般用函式將實現細節封裝,下面介紹幾種常用的方法: 迴圈拆分實現 CREATE FUNCTION [dbo].

SQL Server事務日誌已滿的原因以及解決辦法

錯誤描述:資料庫的事務日誌已滿。若要查明無法重用日誌中的空間的原因 ,請參閱sys.databases 中的 log_reuse_wait_desc 列 。   首先引入一下事務日誌的概念(來自百度百科):   事務日誌是一個與資料庫檔案分開的檔案

SQL Server事務日誌管理的階梯,級別5:以完全恢復模式管理日誌

value letter 的確 維護計劃 臨時 行數 dbo call des 該系列本文是Stairway系列的一部分:SQL Server中事務日誌管理的階梯 當事情進展順利時,沒有必要特別註意事務日誌的功能或工作方式。您只需要確信每個數據庫都有正確的備份機制。當出現問

SQL Server事務日誌管理的步驟,第5級:完全恢復模式管理日誌(譯)

維護計劃 recover 最小 替代 關心 每日 工作方式 檢查 耗時 SQL Server中事務日誌管理的步驟,第5級:完全恢復模式管理日誌 作者:Tony Davis,2012/01/27 系列 本文是進階系列的一部分:SQL Server中事務日誌管理的步驟 當事情進

SQL Server事務日誌管理的步驟,第5級:完全恢復模式管理日誌

語句 targe .aspx 頻率 良好的 popu 這樣的 模式 insert SQL Server中事務日誌管理的步驟,第5級:完全恢復模式管理日誌 作者:Tony Davis,2012/01/27 系列 本文是進階系列的一部分:SQL Server中事務日誌管理的

翻譯:SQL Server事務日誌管理的階梯,級別5:以完全恢復模式管理日誌

作者:Tony Davis, 2012/01/27 該系列 本文是Stairway系列的一部分:SQL Server中事務日誌管理的階梯 當事情進展順利時,沒有必要特別注意事務日誌的功能或工作方式。您只需要確信每個資料庫都有正確的備份機制。當出現問題時,瞭解事務日誌對於採取糾正措施非常重要,尤

翻譯之:SQL Server事務日誌管理的階梯,級別5:以完全恢復模式管理日誌

資料庫中事務日誌管理的階梯,級別5:以完全恢復模式管理日誌 原文連結:http://www.sqlservercentral.com/articles/Stairway+Series/73785/ 作者:Tony Davis, 2012/01/27 本文是樓梯系列的一部分:SQL Server

翻譯:Stairway to Transaction Log Management in SQL Server, Level 5: Managing the Log in Full Recovery Mode SQL Server事務日誌管理的階梯,級別5:以完全恢復模式管理日誌

轉載自:Stairway to Transaction Log Management in SQL Server, Level 5: Managing the Log in Full Recovery Mode SQL Server,By Tony Davis,文章來源:http://www.sqlserve

c#向SQL Server儲存圖片並且從資料庫讀取圖片

前言 資料庫課程設計答辯時,老師提出瞭如果資料是圖片或者其他檔案型別的時候,頓時覺得自己做的管理系統用到的較多的就是Char型別。於是,答辯結束後,就蒐集資料學習,在查詢資料的時候發現,有的一開始並不能看懂,找到一篇文件,自己做了一個測試,然後發現出現了一點小

sql server把一個表查詢出來的資料插入到另外一個表

1、 insertintoA([id], ids,[name], type, time) select[id],null,[name],'dd',getdate()fromBwheretype='dd' 2、 DECLARE @num int,@i int; SET @

SQL SERVER先判斷檢視是否存在,然後建立檢視

如果我們的語句為: IF NOT EXISTS(SELECT 1 FROM sys.views WHERE name='Report_IndividualTicket') BEGIN create view Report_IndividualTicket as SELECT

Sql Server日誌恢復誤刪除或誤Update的資料

最近在研究SQL Server日誌,基本明白日誌的記錄方式。 如果資料庫在建立時 “恢復模式”是“完整”模式,那麼,在對資料庫做的任何操作都會記錄在LDF日誌檔案中,所以有時我們發現LDF日誌檔案要比MDF資料檔案都大。 看一下軟體介面: 軟體基本功能就是讀取LDF日誌檔

VBS將本地的Excel數據導入到SQL Server

vbs將本地的excel數據導入到sql server中 VBS將本地的Excel數據導入到SQL Server中最近有個測試,需要將本地的Excel數據導入到SQL Server中,所以就寫了一個這個腳本,供有需要的同學進行參考。因為在此演示測試,所以準備的數據都比較簡單。我們準備將本地的Excel的A列插

SQL Server的事務與鎖

ani 否則 編譯 什麽 高並發 設置時間 檢測 isolation 管理 了解事務和鎖 事務:保持邏輯數據一致性與可恢復性,必不可少的利器。 鎖:多用戶訪問同一數據庫資源時,對訪問的先後次序權限管理的一種機制,沒有他事務或許將會一塌糊塗,不能保證數據的安全正確讀寫。 死鎖

sql server的全局變量,常用的沒有多少...以後看看就行

detail 技術分享 服務 @* version 變量 名稱 tail identity 全局變量格式: @@***   這些變量有系統維護,不需要我們自己定義,一般都是用來查看信息。 在存儲過程中 用得最多的 @@error,判斷有沒有錯誤信息。 一、@@versio

sql server的開窗函數over、視圖、事物

sel 開啟 row 分數 over 兩個 color span art 一、開窗函數over的作用有兩個: 1、排序order by,row_number,翻頁 2、劃區partition by,結合聚合函數針對某部分數據進行匯總 翻頁的sql server 語句: s

SQL Server 函數的理解總結

處理 操作 標量 之間 div 方式 再看 sel 聚合 T-SQL語言為我們提供了更加靈活的方式操作數據,那就是函數,函數總的分為三大類:標量函數:(傳入一個參數,再傳出一個參數)聚合函數(傳入多個參數,傳出一個參數),表值函數(傳入一個結果集對象,讓我們能夠通過對表的操

Sql Server 查詢存儲過程的修改時間

lai 名稱 lec code str name class 指定 number 1、按最近修改排序所有存儲過程 SELECT [name], [create_date], [modify_date] FROM [sys].[objects] WHERE [type

SQL Server常用的SQL語句

計算 del pri arch 實體完整性 比較 完整 where子句 enc 1、概述 2、查詢概述 3、單表查詢 4、連接查詢 5、帶有exists的相關子查詢 6、SQL的集合操作 7、插入操作 8、刪除操作 9、修改操作 10、數據定義 11、視圖 1、概述