一:背景 1. 講故事 大家都知道資料庫應用程式 它天生需要圍繞著數據文件打轉,諸如包含數據的 .mdf,事務日誌的 .ldf,很多時候深入瞭解這兩類文件的合成原理,差不多對資料庫就能理解一半了,關於 .mdf 的合成前面的文章已經有所介紹,這篇我們來聊一下 .ldf 的一些內部知識,比如 LSN。 ...
一:背景
1. 講故事
大家都知道資料庫應用程式
它天生需要圍繞著數據文件打轉,諸如包含數據的 .mdf
,事務日誌的 .ldf
,很多時候深入瞭解這兩類文件的合成原理,差不多對資料庫就能理解一半了,關於 .mdf
的合成前面的文章已經有所介紹,這篇我們來聊一下 .ldf
的一些內部知識,比如 LSN
。
二:對 LSN 的理解
1. 什麼是 LSN
如果大家玩過 SQLSERVER 的發佈訂閱或者 AlwaysOn 或多或少都見過 LSN
,比如下麵的格式: 00000030:00018090:0002
,這一串編號到底是什麼意思呢?本質上指示的是 .ldf
文件的某一個物理位置上的偏移,畫個圖大概如下:
從圖中可以看到其實是由 虛擬文件號:日誌段起始扇區編號:槽號編號
三部分組成,要瞭解這三部分就需要明白 .ldf
文件是如何進行邏輯劃分的,畫個簡圖如下:
通過上面的圖很容易就能明白其中的邏輯關係,事務日誌文件被劃分成了多個 虛擬文件
,虛擬文件又劃分成了多個 日誌段
,日誌段又劃分成了多個 扇區
,日誌段中日誌記錄位置存儲在 槽號
中,有了這些理論基礎,接下來用一個案例來加深大家的理解吧。
2. 一個案例演示
新建一個 MyLSN
資料庫,再創建一個 test
表,插入 3w 條記錄,sql如下:
CREATE DATABASE MyLSN
GO
USE MyLSN
GO
CREATE TABLE test(a INT IDENTITY, b CHAR(10) DEFAULT 'aaaaaaaaaa')
SET NOCOUNT ON
INSERT INTO test (b) DEFAULT VALUES
GO 30000
SET NOCOUNT OFF
接下來通過 fn_dblog
來查詢和 dbo.test
表相關的事務日誌記錄。
SELECT [Current LSN],
Operation,
Context,
AllocUnitName,
[RowLog Contents 0],
[Log Record],
[Log Record Length]
FROM fn_dblog(NULL, NULL)
WHERE AllocUnitName LIKE '%test%';
從圖中可以看到這是一個 INSERT
的事務日誌記錄,這裡就拿編號 00000030:00000db0:0002
去定位 .ldf 中的物理偏移位置吧,要想獲取物理偏移就要知道下麵偏移值才可以。
- 0x30 虛擬文件號的偏移值是多少 ?
要想知道這個信息,可以用 DBCC loginfo
命令,查看 FSeqNo
下的 StartOffset
偏移值即可,即 0n48 對應的 4071424
,截圖如下:
- 0xdb0 扇區號的偏移是多少?
大家都知道磁碟的扇區是 512byte,sqlserver 為了更好的寫入磁碟,也用了 512byte 這個粒度,所以偏移值就是 512 * 0xdb0
。
綜合上面就能定位到日誌段的物理偏移值為:
lkd> ?0n4071424 + (0n3504*0n512)
Evaluate expression: 5865472 = 00000000`00598000
接下來用 WinHex
來定位 MyLSN_log.ldf
文件偏移 00598000
的位置,定位之前先將資料庫離線。
ALTER DATABASE MyLSN SET OFFLINE
前面的 0x0003
表示該日誌段只有 3 條記錄,後面的 0x019E
表示該日誌段的大小為 414byte
,接下來就是槽號了,槽號位置的物理偏移計算規則如下:
lkd> ? 00598000 + 019E - 1
Evaluate expression: 5865885 = 00000000`0059819d
從圖中可以看到,slot2 的偏移值為 00C8
,即物理偏移值為 005980c8
。
lkd> ? 00598000 + 00C8
Evaluate expression: 5865672 = 00000000`005980c8
從上面框出的內容可以輕鬆的看到,事務日誌中記錄了 Insert 的 aaaaaaaaaa
值,太棒了,起始就是 fn_dblog
查出來的 Log Record
值。
三:總結
對 LSN 有一個深度的理解,對各種資料庫事務日誌暴漲的故障分析都會有一個很好的理論基礎,後面我們再聊這些話題。