Sql Server 中數據庫在BULK_LOGGED/SIMPLE模式下的一些操作會采用最小化日志的記錄方式,以減小tran log落盤日志量從而提高整體性能.
這里我簡單介紹下哪些操作在什么樣的情況下會最小化日志記錄.以及現實生產環境中如何應用最小化日志.
概念:SQL Server在滿足相應條件的基礎上時進行一些特定的操作如Rebuild Index時會進行最小化Tran Log記錄操作,從而改善系統性能.
注意:含最小化操作日志操作段日志無法按時間點恢復(point in time)
需要還原模式為簡單或大容量日志
最小化日志的操作
Create Index,Alter Index Rebulid
Bulk import操作(BCP,Bulk insert)
Select into
Blob數據操作(使用Write等)
Insert select(sql 2008后特定條件下可以)
Merge(特定條件)
應用:實際應用過程中我們實際使用insert select的時候居多,就此介紹
關於insert select操作的最小化日志
聚集表
當聚集表為空時,使用TABLOCK 鎖提示將會最小化日志
當聚集表非空時,無論如何將不會最小化日志
非聚集表
當堆表為空時,使用TABLOCK鎖提示,表中行數據,索引數據(非聚集索引)都會最小化日志
當堆表非空時,使用TABLOCK鎖提示,表中存在非聚集索引,則行數據,索引數據均非最小化日志
注:最小化日志中表非復制表
一些文檔中在堆表有索引非空的情況認為堆行數據會最小化日志,實際是錯誤的.見圖b-2中說明
聚集表實例
聚集空最小化日志 圖a-1
create database testbulk go use master ALTER DATABASE [testbulk] SET RECOVERY BULK_LOGGED WITH NO_WAIT go use testbulk go create table t1(id int not null identity (1,1),dystr varchar(200),fixstr char(500)); go set nocount on declare @i int set @i=0 while(@i<20000) begin insert into t1(dystr,fixstr)values('aaa'+str(RAND()*100000000),'bbb'+str(RAND()*100000000)) set @i=@i+1 end create table tcls ( id int , dystr varchar(200), fixstr char(500) ) go CREATE UNIQUE CLUSTERED INDEX inx_id ON dbo.tcls (id) insert into dbo.tcls with(tablockx) select * from dbo.t1 ----cluster table empty select operation,CONTEXT,[Log Record Length],AllocUnitName from fn_dblog(null,null) where AllocUnitName like '%tcls%'
a-1
聚集非空非最小化日志圖a-2
truncate table tcls DBCC SHRINKFILE (N'testbulk_log' , 0, TRUNCATEONLY) insert into dbo.tcls with(tablockx) values (100000,'aaa','bbb')----made not empty clustered table go insert into dbo.tcls with(tablockx) select * from dbo.t1 ----cluster table not empty select operation,CONTEXT,[Log Record Length],AllocUnitName from fn_dblog(null,null) where AllocUnitName like '%tcls%'
a-2
非聚集索引實例
非聚集非空堆表無索引實例 圖b-1
create table tnoncls ( id int , dystr varchar(200), fixstr char(500) ) go insert into dbo.tnoncls with(tablockx) values (100000,'aaa','bbb')----made not empty heap table no index go insert into dbo.tnoncls with(tablockx) select * from dbo.t1 with(tablockx)----heap table not empty with no index select operation,CONTEXT,[Log Record Length],AllocUnitName from fn_dblog(null,null) where AllocUnitName like '%tnoncls%'
圖b-1
非聚集非空堆表含索引實例 圖b-2
truncate table tnoncls----truncate table DBCC SHRINKFILE (N'testbulk_log' , 0, TRUNCATEONLY) CREATE UNIQUE NONCLUSTERED INDEX inx_id ON dbo.tnoncls (id)----add non clustered index insert into dbo.tnoncls with(tablockx) values (100000,'aaa','bbb')----made not empty heap table with index go insert into dbo.tnoncls with(tablockx) select * from dbo.t1 with(tablockx)----heap table not empty with index select operation,CONTEXT,[Log Record Length],AllocUnitName from fn_dblog(null,null) where AllocUnitName like '%tnoncls%'----both datapage and indexpage full log
b-2
關於trace flag 610
Sql2008新引進的TF,用於非空B-tree結構中仍可最小化日志操作.
關於TF610的使用我個人建議是特殊場景謹慎使用.
一般來說我們在對非空表導入數據的場景,堆表在Online的過程中最小化日志鎖表本身就會影響線上的應用.聚集表數據在插入過程中批量導入的可能性就更低.(好好的聚集表數據批量導入,情況甚微).
TF610本身是為了減少記錄的tran-log大小而設計,並非加快導入而設計.
使用TF610時注意:
1:特定情況下session級打開 dbcc traceon(610)
2:當批量事務提交時所有數據頁需落盤,如果此之前沒有檢查點執行落盤會帶來大量的隨機IO從而導致性能下降,有時甚至不如全日志記錄的插入.
3:避免單個事務過大.超大事務可能導致其他問題.
最小化日志(Minimal Log)最佳實踐
BULK_LOGGED模式:現實生產環境中的數據庫一般是簡單,或者全日志. BULK_LOGGED模式使用常態下寥寥無幾.但當我們的數據操作中存在大量可最小化的日志操作中(如索引重建維護)我們可以開啟BULK_LOGGED模式從而提高操作效率.
例:索引維護
1:選取操作時間窗口:日常全備份前
2:全備份完成后,人工干預執行一次日志備份.
3:修改數據庫模式由Full->BULK_LOGGED
4:大容量日志操作(索引維護)
5:人工干預備份日志
6:重新調整為全日志(模式)
BULK_LOGGED模式下是不會破壞日志鏈,在這樣的模式下我們把Non point time的時間段降到了最低.
注:當數據庫有應用全日志模式的情況下,如鏡像,不宜修改的數據庫模式而破壞應用,當全日志情形下產生的大量日志可能導致實例級的全局問題,應仔細權衡操作.
對有審計需求的數據庫來說,注意具體審計需求:是否需要恢復到時間點.