[SQL SERVER]提高資料處理效能
很久以前我個人有寫一篇 [C#][SQL SERVER] 提高 Insert 效能 ,
基本上要大幅提高資料處理效能,我下面列幾個較重要影響因子
ps:我測試資料庫復原模式採用完整,當處理大量資料時,建議改成大量紀錄以最小化Transaction log為主
1.移除索引(constraint、triggers)
我提供個人實際使用SSIS執行ETL轉約2千萬筆資料
heap table:約 4分鐘 (cpu*2 、ram:8G)
nonheap table:約23分鐘 (cpu*2 、ram:8G)
nonheap table with nonclustered index(*3): 約600分鐘 (cpu*2 、ram:8G)
你可以看到2千萬筆資料新增到空資料表只花不到4分鐘,
如果table有1個clustered index要花23分鐘,
最慘就是總共有4各index(clustered index *1+ nonclustered index*3)花了快10小時才搞定,
所以當你要轉移大量資料時,建議移除所有索引,等資料轉好後再建立索引。
ps:這裡不考慮網路頻寬問題
2.批次處理
盡量避免row by row處理方式,我常看新增100筆資料的邏輯就是for loop 100次,
row by row 處理可說是關聯資料庫效能殺手,
下面簡單測試批次處理。
目前資料庫交易紀錄檔大小
批次處理(一百萬筆一包直接下,但要注意長時間交易)
總共花費約2.6秒
執行後交易紀錄檔大小
批次處理(20萬筆 批次)
資料庫交易紀錄檔大小
DECLARE @batchcount int,@stime varchar(20),@etime varchar(20)
set @batchcount=200000
BEGIN try
set @stime=convert(varchar(20),getdate(),120)
print 'starttiem:'+@stime
WHILE(@batchcount<=1000000)
begin
insert into mytest (EMP_ID,EMP_NAME,SDATE,STIME,EMP_DEP)
select top(200000) EMP_ID,EMP_NAME,SDATE,STIME,EMP_DEP
from rsa241_20130821 s
where not exists
(
select 1 from mytest where EMP_ID = s.EMP_ID
and EMP_NAME=s.EMP_NAME and SDATE=s.SDATE and STIME=s.STIME
and EMP_DEP=s.EMP_DEP
)
set @batchcount=@batchcount+200000
end
set @etime=convert(varchar(20),getdate(),120)
print 'endtime:'+@etime
print '執行時間(ms):'+ cast(DATEDIFF(ms,@stime,@etime) as varchar)
end try
begin catch
print error_message();
end catch
總共花費 9 秒
執行後交易紀錄檔大小
ps:有興趣的人可以for loop 1百萬次測試看看.....
3.排序資料
新增資料時排序方式與來源資料表相同可以提高效能,下面簡單測試。
我先在來源資料建立clustered index
create clustered index cidx on rsa241_20130821(emp_id)
批次處理(一百萬筆一包直接下,但要注意長時間交易)
note:迴圈中避免排序
4.Table Lock
目的資料表加上tablock hint(採shared lock)可以提高data load 效能(採取平行處理)
note:迴圈中避免使用該hint
加上該Hint匯入100百萬筆資料不到1秒就搞定
結論:幾個簡單測試下來,如要提高大量資料處理效能,
基本就是採取批次處理並移除目的資料表相關索引是必須的,
再來就是最小化transaction log並在來源資料表使用tablock hint提高載入效能。