級別: 初級
David Kline, DB2® 供應商支持,PartnerWorld® for Developers, IBM 開發人員技術支持(DTS)中心 — 達拉斯
Nanda Pilaka, DB2® 供應商支持,PartnerWorld® for Developers, IBM 開發人員技術支持(DTS)中心 — 達拉斯
2003 年 2 月 01 日
DB2 確保數據一致性和可恢復性所使用的主要機制之一是事務性日志記錄。本文概述了主要概念,幫助您了解如何能夠控制事務性日志記錄以最優化可恢復性,并且向您介紹了 DB2 UDB V8.1 中新增的日志特性。
簡介
以下文章適用于 IBM® DB2® Universal Database™ for UNIX®、Linux 和 Windows®
任何數據庫管理系統都必須擁有確保數據一致性和可恢復性的機制。關系數據庫系統為確保那些非常重要的特性所使用的眾多機制之一是事務性日志記錄。在本文中,我們將定義和討論事務性日志記錄的類型。我們將詳細討論如何分配日志文件、如何存儲它們,以及您可能會遇到什么樣的錯誤。最后,我們將討論 V8 中可用的新特性,這些特性使事務性日志記錄變得比以往更加可伸縮并且更通用。
事務性日志記錄是什么?
數據庫存儲了供應用程序訪問和處理的數據。那些應用程序會插入、讀取、更新或刪除數據。每一個這樣的活動都是在一個事務中執行的,該事務被 定義成“應用程序過程中一個可恢復的操作序列”。除非已經提交了事務(也稱作“工作單元”),否則它不會影響數據庫。
將數據庫操作組合到事務中只是確保數據一致性解決方案的一半。另一半是稱作 預寫式日志記錄(write-ahead logging)的數據庫管理器實現。不管事務是否被提交,只要它們發生,就會記錄這些事務。在將任何數據從緩沖池寫到數據庫結構之前,事務會從 日志緩沖區(log buffer)寫到 日志文件(事務性日志記錄)。用于記錄事務的文件叫作 事務日志 。
事務性日志記錄的類型不止一種嗎?
DB2 UDB 有兩種可用的日志記錄類型 — 循環(circular)日志記錄和 歸檔(archive)日志記錄。
循環日志記錄
循環日志記錄是數據庫使用的缺省日志記錄策略。在此策略中,一旦日志目錄中最后一個主日志文件被寫滿了,就會將新的事務寫到第一個日志文件中,從而覆蓋現有的日志數據。這些新事務會繼續依次覆蓋每個舊日志文件。這種日志記錄方法確保了所有已提交事務的數據一致性,這樣就可以執行應急恢復。
循環日志記錄通常在數據倉庫環境中使用,在該環境中,恢復數據庫需要的只是恢復數據庫映象的問題。該策略不應該用在線事務處理(on-line transaction processing,OLTP)環境,因為它不可能進行前滾恢復。下面的圖 1 說明了循環日志記錄:
圖 1. 循環日志記錄
歸檔日志記錄
與循環日志記錄相比,當最后一個日志文件寫滿時,歸檔日志記錄過程會創建一個新的日志文件,這樣將來的事務就不會覆蓋現有的日志文件。當初始化數據庫時,系統會在活動日志目錄中分配一定數量、指定大小的主日志文件。這個數量由數據庫配置參數(在 下一節中討論)控制。當主日志文件都寫滿時,就會“根據需要”創建輔助日志文件,直到創建了最大數量的輔助日志文件為止。一旦達到了這個數量,如果需要附加的日志空間,就會發出一個錯誤,指出沒有更多的可用日志文件,所有數據庫活動停止。
利用歸檔日志記錄,就可能采取聯機數據庫備份,在執行這一操作期間,會繼續記錄數據庫活動。如果數據庫崩潰或發生故障,就會使用全備份映象,然后執行使用歸檔日志的前滾操作,通過前滾到日志結尾,將數據庫恢復到時間點狀態或最近的一致狀態,從而恢復數據庫。
有兩種歸檔日志:
- 聯機歸檔日志:它們是駐留在數據庫日志目錄(“online”)中、普通數據庫活動不再需要的日志文件。
- 脫機歸檔日志:它們是已經從數據庫日志目錄移到脫機存儲位置(如備份服務器)、普通數據庫活動不需要的日志文件。
圖 2 說明了歸檔日志記錄:
圖 2. 歸檔日志記錄
有什么參數可以控制日志?
通過數據庫配置參數在數據庫級別上控制事務性日志記錄。以下是影響事務性日志記錄的參數:
LOGRETAIN
該參數使歸檔日志保留在數據庫日志路徑目錄中。通過將它設置成“RECOVERY”來啟用它,從而允許數據庫管理器使用前滾恢復方法。當啟用了 logretain配置參數時,就不需要啟用 userexit 。這兩個參數中的任何一個都足以允許前滾恢復方法。
使用該參數表示覆蓋了循環日志記錄(缺省值)。以下是 logretain的有效值:
- No(缺省值)— 表示不保留日志。
- Recovery— 表示保留日志,且可以用于前滾恢復。此外,如果您使用數據復制,CAPTURE 程序可以將日志中所記錄的更新寫到更改表。
- Capture— 表示只保留日志,這樣 Capture 程序可以將更新寫到更改表。如果沒有裁剪這些日志,那么它們可以用于正向恢復。注:通常僅當為了數據復制而設置數據庫時,才使用 Capture 設置。
如果 logretain設置成“Recovery”或者 userexit設置成“Yes”(請參閱 下一節),將保留活動日志文件,而且這些文件將變成聯機歸檔日志文件,以便在前滾恢復中使用。這稱為日志保留記錄。
在將 logretain設置成“Recovery”和/或將 userexit設置成“Yes”之后,必須對數據庫進行完全備份。這一狀態由 backup_pending標志參數表示。
如果 logretain設置成“No”并且 userexit也設置成“No”,就不能對數據庫執行前滾恢復,而且可恢復性僅限于最新的數據庫備份。
當 logretain設置成“Capture”時,在 Capture 程序完成時,它會調用 PRUNE LOGFILE 命令來刪除日志文件。雖然如果不裁剪日志,這些日志就可以用于正向恢復,但如果您想要確保可以對數據庫執行前滾恢復,就不應該將 logretain設置成“Capture”。
如果 logretain設置成“No”并且 userexit也設置成“No”,就不會保留日志。在這種情況下,數據庫管理器會刪除 logpath目錄中的所有日志文件(包括聯機歸檔日志文件),分配新的活動日志文件,并且回復到循環日志記錄。
當 logretain配置參數設置成“RECOVERY”時,日志文件將保留在活動日志路徑中。活動日志路徑由數據庫配置文件中的“日志文件路徑(Path to Log Files)( logpath)”或“更改的日志文件路徑(Changed Path to Log Files)( newlogpath)”值確定。
USEREXIT
該參數使數據庫管理器調用用戶出口程序來歸檔和檢索日志。啟用了用戶出口之后,就允許前滾恢復。當啟用了 userexit配置參數時,就不需要啟用 logretain。這兩個參數中的任何一個都足以允許前滾恢復方法。
使用該參數表示覆蓋了循環日志記錄(缺省值)。 userexit包含有 logretain的功能,反之卻不成立。
當使用 userexit 配置參數或 logretain配置參數以允許前滾恢復時,活動日志路徑非常重要。當啟用了 userexit配置參數時,會調用用戶出口來歸檔日志文件,并將它們移到活動日志路徑以外的位置。
以下是該參數的有效值:
如果啟用了該參數,無論 logretain參數如何設置,都會執行日志保留記錄。該參數還表示用戶出口程序應該用于歸檔和檢索日志文件。當數據庫管理器關閉日志文件時,會歸檔日志文件。當 ROLLFORWARD 實用程序需要使用日志文件來恢復數據庫時,就會檢索它們。
在啟用了參數 logretain和/或 userexit時,必須對數據庫進行完全備份。這一狀態由 backup_pending標志參數表示。
如果取消選擇這兩個參數,就不能對數據庫進行前滾恢復,因為將不再保留日志。在這種情況下,數據庫管理器會刪除 logpath目錄中的所有日志文件(包括聯機歸檔日志文件),分配新的活動日志文件,并且回復到循環日志記錄。
LOGPRIMARY
該參數指定要創建的主日志的數量。
無論主日志是空的還是滿的,所需的磁盤空間量都是相同的。因此,如果您配置的日志數量比需要的多,那么您就不必要地多使用了磁盤空間。如果您配置的日志太少了,就會遇到“日志滿”情況。當選擇要配置的日志數量時,必須考慮您生成的每個日志的大小,以及您的應用程序是否能處理“日志滿”情況。
如果您對現有數據庫啟用前滾恢復,將主日志的數量更改成當前正在使用的主日志和輔助日志的數量總和,再加 1。對于為了前滾恢復而在數據庫中啟用 long varchar和 LOB字段這樣的附加信息,也會記錄在日志中。
對于 V7.2,總的日志文件大小限制是 32 GB,對于 V8.1,這個限制是 256 GB。即,日志文件的數量(LOGPRIMARY + LOGSECOND)乘以以字節為單位的每個日志文件的大小(LOGFILSIZ * 4096)必須分別小于 32 GB 或 256 GB。
LOGSECOND
該參數指定為恢復日志文件(僅當需要時)而創建和使用的輔助日志文件的數量。請注意,日志文件的總數由以下等式限制:
logprimary+ logsecond<= 128(DB2 UDB V7.2),256(DB2 UDB V8.1)
當主日志文件滿了時,就會按需要每次分配一個輔助日志文件(大小為 logfilsiz),最多達到由該參數控制的最大數量。如果所需的輔助日志文件的數量比該參數允許的數量大,就會將一個錯誤代碼返回到應用程序,并且會停止對數據庫的操作。
LOGFILSZ
該參數確定了每個已配置日志的頁數量。一頁的大小是 4 KB。每個主日志的大小(頁數量)對數據庫性能有直接影響。當將數據庫配置成保留日志,每當寫滿一個日志時,就會發出一個分配和初始化一個新日志的請求。增加日志大小會減少為分配和初始化新日志所需的請求數量。但是,請注意,日志大小越大,格式化每個新日志所花費的時間就越多。格式化新日志對于連接到數據庫的應用程序是透明的,而且也不會影響數據庫性能。
LOGBUFSZ
該參數允許您指定數據庫共享內存的數量,在將日志記錄寫到磁盤之前,用該共享內存作為這些記錄的緩沖區。當發生以下情況之一時,會將日志記錄寫到磁盤:
- 事務提交。
- 日志緩沖區滿了。
- 引起寫操作的其它一些內部數據庫管理器事件。
緩沖日志記錄將導致使日志文件 I/O 更有效,因為將日志記錄寫到磁盤的頻率將更低,而每次寫入磁盤的日志記錄則更多。
MINCOMMIT
該參數允許您延遲將日志記錄寫到磁盤,直到已經執行了所規定的最小數量的提交。當您有多個針對數據庫的應用程序正在運行,并且應用程序在非常短的時間段里請求了許多提交,那么該延遲可以幫助減少與寫日志記錄相關的數據庫管理器開銷,從而提高性能。
這種提交分組只有在該參數的值大于 1 且連接到數據庫的應用程序數量大于該參數的值時才會發生。當執行提交分組時,應用程序提交請求將被掛起,直到以下兩種情況有一種先發生:時間過去一秒或者提交請求的數量等于該參數的值。
NEWLOGPATH
數據庫日志最初創建在名為 SQLOGDIR 的目錄中,該目錄是數據庫目錄的子目錄。可以通過將該配置參數的值更改成指向另一個目錄或設備來更改放置活動日志和將來歸檔日志的位置。如果將數據庫配置成進行前滾恢復,那么就不會將當前存儲在數據庫日志路徑目錄中的歸檔日志移到新的位置。
因為您可以更改日志路徑位置,所以前滾恢復所需的日志可能會在不同的目錄中或在不同的設備上存在。在前滾過程中可以更改此配置參數以允許您訪問多個位置中的日志。
在數據庫處于一致狀態之前,將不會更改對 newlogpath的值。信息性數據庫配置參數 database_consistent表示數據庫的狀態。
注:數據庫管理器每次寫一個事務日志。可以是活動狀態的事務的總大小受數據庫配置參數限制:
日志空間
>= LOGFILSIZ * LOGPRIMARY * 4096 字節
<= LOGFILSIZ * (LOGPRIMARY + LOGSECOND) * 4096 字節 <= 32 GB(對于 V7.2)或 <= 256 GB(對于 V8.1)
如何分配日志文件,將它們存儲在哪里?
如何分配日志文件?
一旦更新了在前一節討論的所有數據庫配置參數,就需要確保所有應用程序從數據庫斷開連接。當應用程序重新連接時,新的設置將生效,日志文件將預先分配到您的磁盤。所分配的日志文件數量基于 logprimary參數值和活動日志目錄中日志文件的總數。
使用 歸檔日志記錄 時,如果您沒有把舊的日志文件從活動日志目錄中移走,它們將累積起來,并與活動日志文件共享該目錄。例如,讓我們假設在活動日志目錄中有五個日志文件。其中兩個日志文件是完全滿的,而且已被提交,因此還有三個日志文件是空閑的。在將 logprimary參數從 五更新成 八之后第一次與數據庫連接時,會多分配五個日志文件到活動日志目錄中,從而確保總共有八個空閑的日志文件(3 個空閑文件 + 5 個新文件 = 8 個空閑文件)。
使用 循環日志記錄時,如果 logretain或 userexit參數被設置成 no,就會重用日志文件。這表示在第一次連接到數據庫時,主日志的總數等于駐留在活動日志目錄中的日志文件的總數。如果我們采用前一個示例并將 logprimary參數從 五更新成 八,那么只會多分配三個日志文件到活動日志目錄中,即使某些日志文件完全是滿的(5 個空閑的 + 3 個新的 = 8)。
正如我們在前一節中討論的,根據 logfilsiz參數為所創建的每個日志文件分配相同的空間。如果更改了 logfilsiz參數值,具有事務性數據的現有日志文件并不受影響,而將創建新的日志文件并將空的日志文件的大小增加到新值。
請注意,反映每個日志文件的大小主要是預先分配的空間,一些日志頭控制字符除外。通過在日志文件中預先分配這個空間,數據庫管理器就不必在它需要該日志文件時進行空間分配。將空間分配到硬盤驅動器將耗費大量時間和資源,因此最好在需要空間時已經有了可用的空間。
logsecond參數是 V7.2 和 V8 之間唯一有區別的參數。在 V7.2 中,該參數只在所有應用程序進行了斷開連接和重新連接之后才生效。而 V8 允許該參數在更新之后立即生效。這并不表示您會在重新連接到數據庫之后立即在日志文件目錄中看到新的日志文件。該參數只會當超過 logprimary值時才會分配日志文件,這種情況最有可能在一系列長時間未提交的事務期間發生。
以下是說明 logsecond 如何影響日志分配的示例。您只是將 logprimary 更新成五,將 logsecond 更新成二(預先分配五個,當需要時再分配兩個)。事務正在運行,并用完所有五個主日志文件,但仍將記錄事務。當需要第六個日志文件時,數據庫管理器將檢查 logsecond 值并將另一個日志文件分配到日志目錄。現在需要第七個日志文件,則分配該文件。由于 logsecond 參數只指定了兩個日志文件,因此在第七個日志文件寫滿之前必須提交事務,否則會返回一個錯誤并且事務將回滾。
那么提交之后,日志文件會發生什么情況?為了保持 logprimary值,數據庫管理器將根據前一個事務中使用了多少日志文件來分配新的日志文件。例如,如果寫滿了三個日志文件,就將創建另三個日志文件以確保空閑日志文件的總數等于 logprimary值。
當所有應用程序從數據庫斷開連接時,會發生什么?當重新連接到數據庫時,前一個連接中的最后一個要放置數據的日志文件將被截斷,使它的大小等于文件中數據的大小。這會除去可用空間,并允許根據上面說明的數據庫配置參數精確地分配空間。
日志文件存儲在哪里?
缺省情況下,日志文件存儲在以下目錄中:
在 Windows 上:c:\<instance name>\NODE0000\SQL00001\SQLOGDIR
在 UNIX 上:<instance home directory>/<instance name>/NODE0000/SQL00001/SQLOGDIR
在上述目錄路徑中,對于所創建的每個數據庫,會有一個 SQLxxxxx(“xxxxx”是以 0 開頭的數字)目錄。如果在 DB2 實例中有多個物理數據庫,就很難知道哪個 SQLxxxxx 目錄屬于哪個數據庫。要解決這個問題,只要輸入以下 DB2 命令:
db2 "list database directory on c:"
|
其中 c: 是數據庫駐留的盤符。
在 UNIX 上,您要指定:
db2 "list database directory on /<instance home directory>"
|
以下是上述命令返回的輸出樣本:
清單 1. DB2 數據庫目錄
Database 1 entry:
Database alias = DWCTRLDB
Database name = DWCTRLDB
Database directory = SQL00001
Database release level = 9.00
Comment =
Directory entry type = Home
Catalog node number = 0
Node number = 0
Database 2 entry:
Database alias = SAMPLE
Database name = SAMPLE
Database directory = SQL00002
Database release level = 9.00
Comment =
Directory entry type = Home
Catalog node number = 0
Node number = 0
Database 3 entry:
Database alias = UTFDB
Database name = UTFDB
Database directory = SQL00003
Database release level = 9.00
Comment =
Directory entry type = Home
Catalog node number = 0
Node number = 0
|
正如以上所示,每個 SQLxxxxx 目錄與一個數據庫名稱相關聯。當然,如果您的數據庫沒有創建在缺省目錄中或者您更改了日志文件路徑,您可以檢查數據庫配置文件中的“日志文件路徑”或 newlogpath參數。您也許還要確保正在尋找的數據庫駐留在正在搜索的實例中。
以下是在 Windows 上存儲日志文件的位置的直觀表示(缺省情況下):
圖 3. 日志文件的 Windows Explorer 視圖
在上圖中,您可以看到一個名為 SQL0003 的數據庫目錄。根據我們從前面的“list database...”命令的輸出判定,該目錄與 UTFDB 數據庫相關聯。
事務性日志記錄會引起錯誤的常見情形
我們已經討論了影響日志記錄的數據庫配置參數以及如何分配日志,但現在應該討論當沒有正確設置參數時您可能遇到的問題。不正確地設置日志參數不僅對發出長時間運行事務的用戶造成嚴重損害,而且還可能損害共享系統的其它用戶。以下是您可能遇到的一些問題:
- 在 IMPORT 操作期間,突然彈出一條警告,它看起來如下:
清單 2. import 操作的警告示例
C:\data>db2 "import from temp2.ixf of ixf create into temp2"
SQL3150N The H record in the PC/IXF file has product "DB2 02.00", date
"20010910", and time "171430".
SQL3153N The T record in the PC/IXF file has name "temp2.ixf", qualifier "",
and source " ".
SQL3109N The utility is beginning to load data from file "temp2.ixf".
SQL3186W Data was not loaded into the database, because the log was full.
SQLCODE "-964" was returned. A commit will be attempted and the operation
will continue if the commit is successful.
SQL0964C The transaction log for the database is full. SQLSTATE=57011
SQL3221W ...Begin COMMIT WORK. Input Record Count = "78".
SQL3222W ...COMMIT of any database changes was successful.
|
由于 IMPORT 操作實質上是使用 SQL 插入進行行移動并關閉了自動提交,所以您會看到上面的警告,說明日志文件已滿并將試圖提交事務。如果將數據庫配置參數 logretain設置成打開(ON),會啟用數據庫的日志恢復,并且在 IMPORT 操作可以繼續之前需要創建新的日志文件。知道您是否需要大日志文件和/或眾多日志文件的組合非常重要,因為要花時間來分配這些日志文件。如果將 logretain設置成 OFF,那么將進行循環日志記錄,從而消除了創建新日志文件的必要性。
如果您正將非常多的行導入數據庫,在每天系統活動較少的時候更新數據庫配置日志記錄參數也許比較好,這樣分配日志文件不會給系統帶來過多壓力。DB2 UDB V7.2 允許分配總共 32 GB 的日志空間,而 V8 允許 256 GB 的海量空間。
另一個考慮事項是使用 LOAD 操作,它允許您對某個表使用 NOT LOGGED INITIALLY 選項。顧名思義,當執行 LOAD 時,該選項不會引起日志記錄操作。但它也阻止了表成為可恢復的,因此在執行 LOAD 之后立即備份數據庫非常重要。請注意,NOT LOGGED INITIALLY 選項只適合于當前命令的執行,數據庫管理器會繼續記錄在 LOAD 操作完成之后發生的事務。
-
當某個應用程序在一個工作單元中執行許多 INSERT、DELETE 或 UPDATE 語句時,會發生另一種常見情況。自動提交被禁用,只有在工作單元完成之后,才會顯式地執行提交。與可以識別日志文件寫滿情況并執行提交的 IMPORT 實用程序不同,應用程序中的邏輯也許還沒有考慮這個問題,那么它將由于以下錯誤而失敗:
SQL0964C The transaction log for the database is full. SQLSTATE=57011
|
因此,如果您的應用程序調用具有罕見長事務的文件,根據您的日志設置包含頻繁的提交操作,或者更新數據庫日志記錄參數,也許是好辦法。
-
當對表執行 RUNSTATS 或 REORG 時,可能出現第三個問題。當到處移動表數據時,RUNSTATS 和 REORG 實用程序都使用日志文件。如果遇到 SQL0964C 錯誤,就需要增加數據庫日志文件參數的值。

 |

|
V8 的新特性
由于 V8 提供了一些很棒的新特性,所以 DB2 日志記錄也向前邁了一大步。以下是其中的一些新特性:
日志記錄可伸縮性— 對于那些喜歡使用非常長的事務的人,DB2 已經將最大活動日志空間從 32 GB(V7.2)增加到 256 GB。這是 logprimary和 logsecond參數的總和可能達到的字節總數。
飄浮事務現在可以超過數據庫日志記錄參數指定的限制,或者如果將 userexit數據庫配置參數設置成打開,那么它甚至可以超過活動日志路徑中的可用磁盤空間。通過將 logsecond更新成 -1(無窮大)來設置該新特性。其想法是由于在長事務期間,日志文件將經常由 userexit 程序歸檔,在活動日志目錄中始終要有新的空間來存放額外的日志文件。在數據庫上運行的飄浮事務的大小或數量沒有限制。但是其缺點是:如果發生回滾,就可能有性能影響,因為 userexit 程序將需要從歸檔日志路徑中檢索未提交的日志文件。此外,如果將 logsecond設置成 -1,新的輔助日志分配將不受( logprimary+ logsecond)<= 256 等式的限制。
DB2_BLOCK_ON_DISK_FULL注冊表變量將被 BLK_LOG_DSK_FUL 替換。當啟用該選項時,在活動日志路徑上發生磁寫盤滿情況時正在運行的應用程序將不會斷開連接。那樣 DBA 就有時間刪除文件或擴大文件系統,從而允許事務完成。當遇到日志寫滿情況,仍允許對數據庫的讀訪問。
日志文件鏡像— DB2 UDB V7 中的 newlogpath2注冊表變量被 DB2 UDB V8 中的 mirrorlogpath數據庫配置參數替換。這一變化將允許數據庫級別上的顆粒度,而不是實例級別上的顆粒度。 newlogpath2變量和 mirrorlogpath參數具有相同的作用 — 它們用于實現雙重或鏡像日志記錄。 mirrorlogpath必須指向全限定路徑名(即,絕對路徑名)。
日志記錄速度更快— 通過異步日志寫操作提高日志記錄器的性能。這在 SMP 環境中特別有益,因為它們能夠利用異步處理。