如何解讀SQL Server日誌(1/3)

来源:http://www.cnblogs.com/Joe-T/archive/2016/08/18/5783247.html
-Advertisement-
Play Games

SQL Server 的事務日誌包含所有數據修改的操作記錄。分析日誌一般作為解決某些問題的最後手段,如查看某些意外的修改。理解和分析日誌內容是件非常困難的事情,fn_dblog通常會輸出非常多的數據,查看也比較困難。我嘗試用一些實例幫助大家更好地分析和理解日誌。 SQL Server 使用Write ...


SQL Server 的事務日誌包含所有數據修改的操作記錄。分析日誌一般作為解決某些問題的最後手段,如查看某些意外的修改。理解和分析日誌內容是件非常困難的事情,fn_dblog通常會輸出非常多的數據,查看也比較困難。我嘗試用一些實例幫助大家更好地分析和理解日誌。

SQL Server 使用Write-ahead logging (WAL)方式保證任何數據變更的日誌要比數據變更先發生。同時,對資料庫中任何數據變更操作都會被記錄在日誌中。註意所有的數據對象(tables, views, stored procedures, users, permissions etc)是元數據,但是也數據。所以對資料庫中任何對象的變更操作都會被記錄在日誌中。註意,像最小化日誌操作、大容量日誌操作和Truncate(謠傳的“無日誌操作”)都是事務性的,都會記錄在日誌中。

事務日誌中的每一條日誌記錄由LSN(Log Sequence Number)唯一標識。LSN是有序的,如果LSN2大於LSN1,則LSN2的日誌所代表的數據修改操作發生在LSN1之後。

下麵用一個例子來開始分析。將使用未公開的函數sys.fn_dblog,它能夠讀取當前資料庫活動部分的事務日誌。此函數返回的 [Transaction ID] 欄位表示SQL Server 為每個事務分配的事務ID,同一個事務所有的日誌記錄具有一樣的事務ID。

use master 
go
create database LogTest
go
use LogTest
go
create table demotable (
    id int not null identity(1,1) primary key, 
    data char(20), 
    created_at datetime default getutcdate());
go

insert into demotable (data) values ('standalone xact');
go 5


begin transaction
go

insert into demotable (data) values ('one xact');
go 5

commit;
go

delete from demotable
where id in (2,5,6,9);
go

sys.fn_dblog返回的[operation]表示進行的是什麼操作,我們先看看一個非常重要的操作: LOP_BEGIN_XACT。它標記一個事務的開始,也是日誌中唯一包含事務開始時間的記錄,同時還包含發出語句用戶的SID。

select [Current LSN], [Operation], [Transaction ID], [Parent Transaction ID],
    [Begin Time], [Transaction Name], [Transaction SID]
from fn_dblog(null, null)
where [Operation] = 'LOP_BEGIN_XACT'

Lop_Begin_Xact

SQL Server總是對數據操作使用事務,不管是用戶定義的顯示事務或者是自動的隱式事務。 LSN:00000023:00000033:0001開始事務0000:00000352,事務名叫做CREATE TABLE。LSN開始了INSERT事務0000:00000356,這就是腳本中的5個單獨的INSERT語句,每個INSERT是一個隱式事務。它還還包括事務0000:00000359,0000:0000035a,0000:0000035b,0000:0000035c。觀察事務ID,會發現者是按1增長的16進位數。再看LSN 00000023:00000061:0001的事務0000:0000035d,它叫做user_transaction。這是腳本中用戶定義的INSERT的顯式事務。它從BEGIN TRANSACTION開始,包括了5個INSERT,而不像之前產生5個INSERT隱式事務。最後LSN 00000023:00000070:0001開始了DELETE事務0000:00000360。

還發現有兩個SplitPage的Parent Transaction ID等於CREATE TABLE的事務ID。頁拆分是B-TREE根據排序鍵維護數據順序的一種方式。註意,這裡的兩頁拆分是因為CREATE TABLE插入元數據導致內部元數據表的頁拆分,而不是用戶表。

在第一個INSERT事務後接著一個事務Allocate Root。正常情況,創建表時,不會分配頁給它。第一個INSERT會觸發分配第一個頁配給表。分配操作由單獨的事務完成,並且會立即提交。即使觸發頁分配的那個INSERT事務被回滾或者延遲提交,也不會影響其它的數據插入操作。從這裡也可以看出,一個會話中,可以開始和提交獨立於會話主事務之外的事務的,只是這個功能沒有提供給T-SQL,只是內部使用。

Transaction SID 列表示啟動事務的登錄名的SID,可以用SUSER_SNAME()函數獲取到實際的登錄名。

觀察一個事務的詳細日誌內容

select [Current LSN], [Operation], 
    [AllocUnitName], [Page ID], [Slot ID], 
    [Lock Information],
    [Num Elements], [RowLog Contents 0], [RowLog Contents 1], 
    [RowLog Contents 2]
from fn_dblog(null, null)
where [Transaction ID]='0000:00000356'

FirstInsert

我們來看看第一個INSERT事務:356的詳細日誌內容。很明顯,356事務有4條日誌。每個事務必須以LOP_BEGIN_XACT開始,以一條日誌結,通常是LOP_COMMIT_XACT。還有一條關於鎖的日誌(LOP_LOCK_XACT)和一條關於實際數據修改的日誌(LOP_INSERT_ROWS)。

數據修改操作(如LOP_INSERT_ROWS)總是會記錄它操作的物理內容(PageID,SlotID)和對象:分配單元(Allocation Unit ID)和分區ID(Partition ID)。查看AllocUnitName列是確定哪一個對象被修改的最簡單的方式。Page ID 和Slot ID告訴我們哪個頁的哪一個槽位被事務修改了。16進位90=144十進位,0=0。我們通過DBCC PAGE來看看144頁的Slot 0。

dbcc traceon(3604,-1);
dbcc page(7,1,144,3);
------------------------------------------------------------------------
Slot 0 Offset 0x60 Length 39

Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP    Record Size = 39

Memory Dump @0x00000000117AA060

0000000000000000:   10002400 01000000 7374616e 64616c6f 6e652078  ..$.....standalone x
0000000000000014:   61637420 20202020 797d6f00 64a60000 030000    act     y}o.d......

Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4

id = 1                              

Slot 0 Column 2 Offset 0x8 Length 20 Length (physical) 20

data = standalone xact              

Slot 0 Column 3 Offset 0x1c Length 8 Length (physical) 8

created_at = 2016-08-16 06:45:55.390

Slot 0 Offset 0x0 Length 0 Length (physical) 0

KeyHashValue = (8194443284a0)       
Slot 1 Offset 0xae Length 39

從輸出的頁,我們確定144頁的Slot 0 的確存儲著第一個INSERT的內容,也佐證了sys.fn_dblog內容是正確的。日誌中的這部分內容可以幫助我們解決一個問題:現在知道某個行的位置(頁ID和槽ID),想要找出是哪一個事務修改了這一行?可以通過搜索日誌記錄中的Slot ID和Page ID找到相關事務。但是,這個方法對於B-TREE來說是非常困難的。因為B-TREE發生頁拆分時會改變行的物理地址,在匹配時就會很困難了。

Lock Information列的完整內容:

HoBt 72057594039042048:ACQUIRE_LOCK_IX OBJECT: 7:245575913:0 ;
ACQUIRE_LOCK_IX PAGE: 7:1:144 ;
ACQUIRE_LOCK_X KEY: 7:72057594039042048 (8194443284a0)

其中有表的Object ID,頁ID和索引鍵的鍵鎖信息。對於B-TREE,鍵鎖就是鍵值的HASH值,所以通過它能定位到數據行(就算發生頁拆分,但是鍵值是不會變的)。

select %%lockres%%, *
from demotable
where %%lockres%% = '(8194443284a0)';

                      id          data                 created_at
--------------- --------- -------------------- -----------------------
(8194443284a0)        1          standalone xact      2016-08-16 06:45:55.390

通過鍵鎖信息,我們正確定位到第一個INSERT的行。註意,HASH值存在HASH碰撞的可能,即不同的鍵值生成了同樣的HASH值。碰撞的概率是非常低的,如果發生, 上面的查詢會返回多行。

總結

  1. 原文地址:How to read and interpret the SQL Server log ,非逐字翻譯,在自己理解的基礎上的意譯,有增和刪內容。
  2. 解析日誌內容,通常只會在少數特殊的場景用到,但會對SQL Server的理解有幫助。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 用批處理在命令行狀態下調用查詢分析器來執行這個sql文件里的語句。下麵就是sqlserver幫助里對於查詢分析器(isqlw)命令行參數的解釋:isqlw 實用工具(SQL 查詢分析器)使您得以輸入 Transact-SQL 語句、系統存儲過程和腳本文件。通過設置快捷方式或創建批處理文件,可以啟動預 ...
  • 介紹 1.下載解壓 下載地址:http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.14-winx64.zip 將下載的mysql解壓重命名放在C:\Program Files\MySQL\MySQL Server 5.7” 2.創建目錄 創建 ...
  • 在SQL Server中使用OPENROWSET訪問ORACLE資料庫時,你可能會遇到各種坑,下麵一一梳理一下你會遇到的一些坑。 1:資料庫沒有開啟"Ad Hoc Distributed Queries"選項,那麼你就會遇到下麵坑。 SELECT TOP 10 * FROM OPENROWSET('... ...
  • 一、功能介紹 1.MySQL Servers 該功能是mysql主要的服務,也是必須安裝的功能。 2.Mysql WorkBench 這個是mysql的客戶端工具,可以單獨下載安裝程式安裝。 3.Mysql Notifier 該功能可以控制mysql啟動,安裝了該功能會在電腦右下角的圖標中有控制my ...
  • 前幾天在開發一個系統,需要用到隨機字元串,但是mysql的庫函數有沒有直接提供,就簡單的利用現有的函數東拼西湊出隨機字元串來.下麵簡單的說下實現當時. 1.簡單粗暴. 上訴示例產生的是:6位長度的隨機字元串. 函數解釋: rand() :產生 0-1之間的小數,簡稱種子.rand()*25 產生的數 ...
  • MySQL binlog記錄的所有操作實際上都有對應的事件類型的,譬如STATEMENT格式中的DML操作對應的是QUERY_EVENT類型,ROW格式下的DML操作對應的是ROWS_EVENT類型。 首先,看看源碼中定義的事件類型 源碼位置:mysql-5.7.14/libbinlogevents ...
  • 在老系統中該函數調用一次需要話20多秒到30秒左右。 拿到sql之後,首先要確定思路。不能著急這下手。 1. 首先查看各個表的數據量: select count(*) from xxx; 發現只有 a21 的數據量達到了十幾萬,其他表數據量都比較小。所以重點是 a21表,仔細閱讀了一遍函數的定義,發 ...
  • 在SQL Server中,在鏈接伺服器中調用表值函數(table-valued function)時,會遇到下麵錯誤: SELECT * FROM LNK_TEST.TEST.DBO.TEST(12) 消息 4122,級別 16,狀態 1,第 1 行 Remote table-valued func... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...