爲何事務日誌自動增加會下降你的性能

在這篇文章裏,我想詳細談下爲何你要避免事務日誌(Transaction Log)上的自動增加操做(Auto Growth operations)。不少運行的數據庫服務器,對於事務日誌,用的都是默認的日誌文件大小和自動增加設置。人們有時會很依賴自動增加機制,由於它們恰好能正常工做。固然,若是它正常工做的話,你沒必要太關注它,但很快你會發現會有問題出現。web

只依賴於事務日誌的自動增加機制總不是個好主意。首先它會致使嚴重的日誌碎片(Log Fragmentation),在SQL Server啓動期間,在你數據庫上執行崩潰恢復(Crash Recovery)時會有很大的負面影響。另外,在你數據庫裏寫入事務須要等待,只要事務日誌觸發了自動增加機制。sql

當事務日誌的自動增加機制發生時,SQL Server總要零初始化新塊,這個會在文件末尾加上。這和你的SQL Server實例是否用即時文件初始化(Instant File Initialization)特權——事務日誌總會零初始化。這上面的緣由很是明顯:當SQL Server在過去已經完成事務日誌的環繞式處理(wrap-around ),崩潰恢復(Crash Recovery)須要知道在哪裏停。數據庫

零初始化的問題是會佔用更多的時間(取決與你的自動增加率,還有你的存儲速度)。在此期間沒有別的事務能夠寫事務日誌記錄到事務日誌。在事務日誌管理器上會有閂鎖形成的阻塞。所以你的寫入事務會進入掛起狀態(直到它們得到須要的閂鎖),它們就等啊,等啊,等啊,直到你的事務日誌自動增加完成。讓咱們用一個簡單的例子演示下。windows

首先我爲這個演示建立一個新的數據庫。對於這個數據庫,這裏我不用默認的設置,對於事務日誌,我指定了10GB的自動增加係數。這個的確是個很差的作法,但我只是用它來展現這個設置的反作用。請不要在你的生產數據庫裏使用這個錯誤配置!!! 服務器

 1 -- Create a new database with 10 GB Auto Growth for the Transaction Log
 2 CREATE DATABASE AutoGrowthTransactionLog ON PRIMARY 
 3 (
 4     NAME = N'AutoGrowthTransactionLog', 
 5     FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\AutoGrowthTransactionLog.mdf',
 6     SIZE = 5120KB, 
 7     FILEGROWTH = 1024KB
 8 )
 9 LOG ON 
10 (
11     NAME = N'AutoGrowthTransactionLog_log',
12     FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\AutoGrowthTransactionLog_log.ldf',
13     SIZE = 1024KB,
14     FILEGROWTH = 10240000KB -- 10 GB Auto Growth!
15 )
16 GO

 下一步裏我在數據庫裏建立2個表。第1個表我經過插入一些日誌來快速填充個人事務日誌。在事務日誌自動增加階段,咱們在第2個表裏插入新的記錄來證實這個事務會被自動增加機制阻塞。session

 1 -- Create a new table, every records needs a page of 8kb
 2 CREATE TABLE Chunk
 3 (
 4     Col1 INT IDENTITY PRIMARY KEY,
 5     Col2 CHAR(8000)
 6 )
 7 GO
 8 
 9 -- Another simple table
10 CREATE TABLE Foo
11 (    
12     Bar INT NOT NULL
13 )
14 GO

如今咱們已經建立了必須的數據庫對象,因次我能夠經過新的沒有當即提交的事務來填充事務日誌:函數

1 -- Begin a new transaction, that blocks the 1st VLF in the Transaction Log
2 BEGIN TRANSACTION
3 INSERT INTO Chunk VALUES (REPLICATE('x', 8000))
4 GO

由於咱們如今有了進行中,沒提交的事務,SQL Server不能重用那部分事務日誌,即這個事務存儲的事務日誌。它們有須要回滾的可能。所以如今我經過不一樣的會話插入66條其餘記錄來填充事務日誌:性能

1 INSERT INTO AutoGrowthTransactionLog.dbo.Chunk VALUES (REPLICATE('x', 8000))
2 GO 66

最後在第一個會話裏提交咱們的事務:測試

1 COMMIT

這意味着在咱們面前有一個幾乎滿的的事務日誌,咱們能夠經過DBCC LOGINFO來驗證:spa

1 DBCC LOGINFO

如今當咱們往表裏插入兮的記錄時,事務日誌已經沒有可用空間了,SQL Server進入事務日誌的自動增加。

1 -- This statement will trigger the Auto Growth mechanism!
2 INSERT INTO Chunk VALUES (REPLICATE('x', 8000))
3 GO

在自動增加期間的同時,爲了監控發生了什麼,咱們能夠在SSMS裏打開新的一個會話窗口,嘗試在第2個表插入另外的記錄——表Foo

1 -- This statement is now blocked by the Auto Growth mechanism.
2 INSERT INTO Foo VALUES (1)
3 GO

這個SQL 語句會阻塞,由於事務要寫入事務日誌記錄的事務日誌,當前不可用。爲了進一步分析這個阻塞情形,你能夠打開第3個會話窗口,執行下列2個SQL語句:

1 -- Analyze the blocking situation
2 SELECT wait_type, * FROM sys.dm_exec_requests
3 WHERE session_id IN (54, 55)
4 
5 SELECT wait_type, * FROM sys.dm_os_waiting_tasks
6 WHERE session_id IN (54, 55)
7 GO

(額,俺本機測試失敗………………)

從代碼裏能夠看到,我用2個DMV sys.dm_exec_requests 和 sys.dm_os_waiting_tasks對2個會話都進行了跟蹤——觸發自動增加的會話,和被自動增加機制阻塞的會話。在這裏,觸發自動增加的會話裏有所謂的搶佔等待類型(Preemptive Wait Type)——PREEMPTIVE_OS_WRITEFILEGATHER。搶佔等待類型是由SQL Server返回的等待類型,當SQL Server 執行一個WIN32 API函數在調度機制以外時。這裏自動增加是經過WriteFileGather的WIN32 API函數完成的。

INSERT語句嘗試在Foo表裏插入新的記錄出現LATCH_EX等待類型。如你從DMV sys.dm_os_waiting_tasks 裏的resource_description列所見,在SQL Server的日誌管理器上須要得到閂鎖。你能夠經過查詢DMV sys.dm_os_latch_stats 限制lactch class爲LOG_MANAGER再次確認。在那個特定閂鎖上你會看到一些等待。那個閂鎖是事務獲取的,由事務日誌的自動增加觸發,只要這個閂鎖要得到,每一個其餘寫事務都會被阻塞。所以在系統上有大量等待時間時,這暗示這在事務日誌裏當前有自動增加問題須要處理。

但願我已經用這個日誌說服你,依賴於事務日誌的自動增加機制並非最好的解決方案。用這個簡單的例子能夠看到,在你數據庫裏每一個被自動增加操做阻塞的寫入事務會發生阻塞,這確定會傷及你數據庫的吞吐量和擴展性。爲了保證你有很好的事務日誌性能,你能夠最佳想實踐下這個文章

感謝關注! 

參考文章:

https://www.sqlpassion.at/archive/2014/01/07/why-transaction-log-auto-growths-are-degrading-your-performance/

相關文章
相關標籤/搜索