SQL Server事務日誌分析sql
fn_dblog()和fn_dump_dblog()函數介紹數據庫
SQL Server有兩個未公開的函數fn_dblog()和fn_dump_dblog()很是有用而且提供的信息量很大。你能夠使用這些函數來獲取100多列大量的有用信息。ide
fn_dblog()用於分析數據庫當前的事務日誌文件,它須要兩個參數,分別爲事務開始LSN和結束LSN,默認爲NULL,表示返回事務日誌文件的全部日誌記錄。函數
例如:spa
SELECT * FROM fn_dblog(null,null);
fn_dump_dblog()用於分析數據庫的事務日誌備份文件,該函數須要的參數不少,但咱們只須要傳入備份文件的完整路徑名稱,其餘參數使用默認值DEFAULT。3d
例如:日誌
SELECT * FROM fn_dump_dblog ( NULL, NULL, 'DISK', 1, 'D:\Pay\Pay_201707280400_LOG.trn', DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT);
再來看看下圖多個事務操做寫入到事務日誌文件的表現:orm
重要數據輸出列值對象
咱們再來分析下100多列輸出中的幾個重要列:blog
[Transaction Name]
該列描述該事務操做的類型,主要值有:
INSERT、UPDATE、DELETE、DROPOBJ
次要值有:
AllocPages、SplitPage、AllocHeapPageSysXactDML、UpdateQPStats、Backup:CommitLogArchivePoint、BTree Split/Shrink等。
典型的應用是經過DROPOBJ值來查找對象刪除操做。
[Operation]
該列描述日誌裏記錄的操做的具體類型,主要值有:
LOP_BEGIN_XACT、LOP_COMMIT_XACT、LOP_INSERT_ROWS、LOP_DELETE_ROWS、LOP_MODIFY_ROW、LOP_MODIFY_COLUMNS
次要值有:
LOP_BEGIN_CKPT、LOP_END_CKPT、LOP_XACT_CKPT、LOP_LOCK_XACT、
LOP_DELETE_SPLIT、LOP_EXPUNGE_ROWS、LOP_MODIFY_HEADER、LOP_FORMAT_PAGE、LOP_COUNT_DELTA、LOP_HOBT_DELTA、LOP_INSYSXACT、LOP_INVALIDATE_CACHE、LOP_MIGRATE_LOCKS、LOP_SET_BITS、LOP_SET_FREE_SPACE、LOP_SHRINK_NOOP、LOP_TEXT_INFO_BEGIN、LOP_TEXT_INFO_END
[Begin Time]
事務操做的開始時間。
[PartitionID]
具體操做的哪一個分區,能夠關聯查詢到具體影響的哪一個表或索引。
[TRANSACTION SID]
該事務操做的用戶SID,能夠經過SUSER_SNAME()函數轉換爲用戶名。
具體示例分析
再來看一個具體事務操做:
SELECT [Current LSN], [Transaction ID], [Transaction Name], [Operation], [Begin Time], [PartitionID], [TRANSACTION SID] FROM fn_dump_dblog ( NULL, NULL, 'DISK', 1, 'D:\Pay\Pay_201707280400_LOG.trn', DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT, DEFAULT) WHERE [Transaction ID]='0000:5c9b41e2';
根據[Transaction Name]爲INSERT知道這是一個插入操做,具體哪條是插入的數據行,哪條是索引行,能夠根據後面的PartitionID再去關聯查詢到。
根據[TRANSACTION SID]能夠查詢到操做的用戶:
SELECT SUSER_SNAME(0x017017A631B52141B2338990DCFFADCC);
根據[PartitionID]查詢到操做的對象:
SELECT so.name FROM sys.objects so INNER JOIN sys.partitions sp on so.object_id = sp.object_id WHERE partition_id in( 72057594041204736, 72057594070630400);
根據partition_id還能夠更詳細的查看是數據行仍是索引行:
--查看某個表的具體數據分佈 SELECT DISTINCT so.name AS 'table_name', so.object_id,sp.partition_id,si.name AS 'index_name',internals.type_desc,internals.total_pages, internals.used_pages, internals.data_pages,first_iam_page, first_page, root_page FROM sys.objects so INNER JOIN sys.partitions sp ON so.object_id = sp.object_id INNER JOIN sys.indexes si ON sp.object_id = si.OBJECT_ID AND sp.index_id = si.index_id INNER JOIN sys.allocation_units sa ON sa.container_id = sp.hobt_id INNER JOIN sys.system_internals_allocation_units internals ON internals.container_id = sa.container_id WHERE so.object_id = object_id('NotificationRecord');
--查看某個表的索引詳細信息 SELECT TableId=O.[object_id], TableName=O.Name, IndexId=ISNULL(KC.[object_id],IDX.index_id), IndexName=IDX.Name, IndexType=ISNULL(KC.type_desc,'Index'), Index_Column_id=IDXC.index_column_id, ColumnID=C.Column_id, ColumnName=C.Name, Sort=CASE INDEXKEY_PROPERTY(IDXC.[object_id],IDXC.index_id,IDXC.index_column_id,'IsDescending') WHEN 1 THEN 'DESC' WHEN 0 THEN 'ASC' ELSE '' END, PrimaryKey=CASE WHEN IDX.is_primary_key=1 THEN N'√'ELSE N'' END, [UQIQUE]=CASE WHEN IDX.is_unique=1 THEN N'√'ELSE N'' END, Ignore_dup_key=CASE WHEN IDX.ignore_dup_key=1 THEN N'√'ELSE N'' END, Disabled=CASE WHEN IDX.is_disabled=1 THEN N'√'ELSE N'' END, Fill_factor=IDX.fill_factor, Padded=CASE WHEN IDX.is_padded=1 THEN N'√'ELSE N'' END FROM sys.indexes IDX INNER JOIN sys.index_columns IDXC ON IDX.[object_id]=IDXC.[object_id] AND IDX.index_id=IDXC.index_id LEFT JOIN sys.key_constraints KC ON IDX.[object_id]=KC.[parent_object_id] AND IDX.index_id=KC.unique_index_id INNER JOIN sys.objects O ON O.[object_id]=IDX.[object_id] INNER JOIN sys.columns C ON O.[object_id]=C.[object_id] AND O.type='U' AND O.is_ms_shipped=0 AND IDXC.Column_id=C.Column_id where O.name='NotificationRecord';