什麼是事務日誌算法
事務日誌的組成數據庫
事務日誌大小維護方法post
Truncateui
Shrinkspa
索引碎片日誌
總結code
什麼是事務日誌
Transaction log 是對數據庫管理系統執行的一系列動做的記錄,並利用這些記錄來保證在遭遇硬件故障,災難狀況下ACID的可用性。從物理上來講,事務日誌就是一個記錄對數據庫更新操做的文件。
事務日誌的組成
SQL Server 數據庫引擎在內部將每一個物理文件分爲多個虛擬日誌文件。虛擬日誌文件沒有固定大小和固定數量,這兩個值是由數據庫引擎動態決定的。blog
事務日誌是一個循環文件。當數據庫建立之後,邏輯日誌從物理日誌文件的起始位置開始。新的日誌記錄被添加到邏輯日誌的後面直到物理日誌文件的末尾。日誌截取會把LSN(Log Sequential Number)比最小恢復日誌序列號(MinLSN)早的虛擬日誌記錄給釋放掉。MinLSN 是要實現一次成功的數據庫範圍回滾所須要的最小日誌記錄。排序
事務日誌的結構以下:索引
每一個虛擬日誌有多條記錄組成,每條記錄都有一個LSN(一條SQL 原子語句)。分析上面的圖咱們能夠看到虛擬日誌1和2被截取了,這說明虛擬日誌1和2中的事務已經成功提交(並不表明數據修改已經物理上被更新到數據庫文件中,由於有一個涉及磁盤IO效率問題)。
當邏輯日誌到達物理日誌文件的末尾之後,新的日誌記錄會循環到物理日誌的開頭位置,以下圖所示:
只要邏輯日誌尾不超過邏輯日誌頭,這種循環就永遠不會結束。若是舊的日誌記錄可以被週期性/頻繁的截取,那麼就會有足夠的可用空間留給新添加的日誌記錄,這樣整個物理日誌文件大小就會保持在一個相對穩定的範圍,反之則會出現如下兩種狀況之一:
- 若是設置了自動增加,則會按照增加百分比/值來增長物理日誌文件大小,這就是爲何咱們的事務日誌文件常常會變得很大。
- 若是沒有設置自動增加或者存儲事務日誌文件的磁盤沒有可用空間了,那麼SQL Server 會拋出9002 錯誤。
注意:若是一個數據庫有多個事務日誌文件(LDF), 那麼除非第一個事務日誌文件沒有可用空間了,不然不會使用其餘的事務日誌文件。
事務日誌大小維護方法
Truncate
由上面的描述咱們能夠大概知道Truncate 就是將事務日誌中的能夠回收的邏輯日誌文件標識爲能夠再次使用,具體的觸發條件分爲兩種狀況:
- 對於Recovery Mode 爲Simple 的數據庫來講,每次事務以後會自動執行CheckPoint 操做,將提交完的邏輯日誌空間清空,以保證事務日誌文件大小最小。這等同於事務日誌中沒有日誌記錄,那麼能夠理解成沒有事務日誌,一旦發生災難,可能會致使數據丟失。
- 對於Recovery Mode 爲Full/Bulked-Log 來講,每次進行Backup Log 操做都會自動執行CheckPoint 操做,將提交完的邏輯日誌空間清空。換句話說咱們能經過週期性的日誌備份來維護事務日誌文件大小的可控。
打開查詢分析器,執行如下查詢:
如今對數據庫執行一第二天志備份, 而後執行LOGINFO命令:
能夠看到邏輯日誌1,2的狀態被標識爲0,這意味着邏輯日誌1和2均可以被重用了。可是咱們再觀察下邏輯日誌4的偏移和大小,這兩個值並無變,也就意味着整個事務日誌大小仍然爲:
1384448+712704=2,097,152 字節(純邏輯日誌文件大小 + 8192字節頭)
Shrink
Shrink 便是收縮日誌,Truncate 操做並不會改變整個事務日誌文件大小,只會將本來活躍的邏輯日誌標記爲不活躍以供下次使用;
Shrink 操做會徹底破壞索引的物理結構,致使產生索引碎片,使索引失效。
爲何會這樣呢?由於數據文件收縮操做每次執行都會使用GAM 位圖算法來找到文件中最大文件,而後將它儘量地移動到文件頭,如此反覆(相似冒泡排序)。這樣就會徹底打亂聚簇索引的順序,致使它由一個秩序進展的索引變成雜亂無章的索引。
對於DBCC SHRINKFILE, DBCC SHRINKDATABASE, 以及auto-shrink 它們都會產生同樣的後果,引入索引碎片, 致使大量I/O操做,CPU 消耗以及事務日誌的過載。
來看一個例子,先建立一個數據庫:
USE MASTER; GO IF DATABASEPROPERTYEX ('DBMaint2008', 'Version') > 0 DROP DATABASE DBMaint2008; CREATE DATABASE DBMaint2008; GO USE DBMaint2008; GO SET NOCOUNT ON; GO -- Create the 10MB filler table at the 'front' of the data file CREATE TABLE FillerTable (c1 INT IDENTITY, c2 CHAR (8000) DEFAULT 'filler'); GO -- Fill up the filler table INSERT INTO FillerTable DEFAULT VALUES; GO 1280 -- Create the production table, which will be 'after' the filler table in the data file CREATE TABLE ProdTable (c1 INT IDENTITY, c2 CHAR (8000) DEFAULT 'production'); CREATE CLUSTERED INDEX prod_cl ON ProdTable (c1); GO INSERT INTO ProdTable DEFAULT VALUES; GO 1280
而後查詢索引碎片百分比:
-- check the fragmentation of the production table SELECT [avg_fragmentation_in_percent] FROM sys.dm_db_index_physical_stats ( DB_ID ('DBMaint2008'), OBJECT_ID ('ProdTable'), 1, NULL, 'LIMITED'); GO
經過上面截圖能夠發現初始狀況下索引的碎片百分比僅0.5%, 這種狀況已經很是好了。
咱們把剛纔建立的表刪掉並經過DBCC Shrink 操做回收空間:
能夠看到索引碎片百分比已經接近100%,這樣狀況下索引不但不會爲咱們查詢數據提升效率,反而會加劇系統的負擔。
索引碎片
SQL Server 提供了兩種命令來處理上述狀況:
a. Rebuild 索引
USE DBMaint2008; GO ALTER INDEX ALL ON ProdTable REBUILD GO
b. Reorganize索引
USE DBMaint2008; GO ALTER INDEX ALL ON ProdTable REORGANIZE GO
咱們來看一下對上面索引碎片接近100%的表進行索引重組後的效果:
能夠看到數據庫表的索引恢復了正常,可是這種方案也不徹底推薦,對於數據量很大的聚簇索引來講,重建/重組織索引會產生大量I/O, CPU 消耗,因此平時好好維護索引纔是咱們應該作的。
總結
- Truncate 只會將虛擬日誌的活躍部分變成非活躍部分,這樣就能夠重用這些空間,它並不會影響總體事務日誌大小;對於Simple 數據庫來講每次事務結束後都會執行CheckPoint 檢查,對於Full/Bulked-Log 數據庫來講每第二天志備份操做之後都會執行CheckPoint 檢查。
- Shrink 操做能夠減少日誌文件的物理文件大小,同時也致使日誌文件被從新組織,聚簇索引和非聚簇索引的原有結構都會被打亂,致使產生索引碎片,繼而帶來的影響是索引失效,磁盤I/O 和 CPU 的資源消耗加大,對於Shrink 咱們儘可能避免使用它,一旦無可奈何使用Shrink 操做,咱們也要按照實際狀況決定是否須要重建/重組織索引。
總之,使用週期性的日誌備份來維護咱們的事務日誌文件大小是很是明智的。