原文出處:https://blogs.msdn.microsoft.com/sqlcat/2013/09/16/top-10-sql-server-integration-services-best-practices/sql
譯:數據庫
多少人據說過「SQL Server Integration Services(譯註:如下簡稱SSIS)不能擴展」的傳說?咱們要反問的是「你的系統是否有必要擴展到每秒可以處理超過450萬行交易記錄?」SSIS是能夠適應最極端環境的高性能ETL平臺。而且正如在SSIS ETL性能世界記錄所記載,SSIS能夠處理每秒450萬規模的銷售交易記錄。緩存
1.SSIS是基於內存的數據管道,所以請確保全部的轉換髮生在內存中。服務器
在SQL Server的功能中加入SSIS的目的是提供一個有彈性且穩定的數據管道,以便於在內存中高效地執行逐行計算和數據校驗。網絡
SSIS自己的數據轉換應該在內存中處理,然而數據抽取和載入階段卻會涉及磁盤(會產生相應的讀寫)。一旦數據轉換操做溢出到磁盤上,ETL性能將會有顯著降低。爲了確保全部的轉換都可以在內存中處理,請仔細構建包以分割並過濾數據。併發
確認包是否駐留在內存中的一個好辦法是檢查SSIS緩存池相關的性能計數器,它的初始值是0,超過0就意味着SSIS引擎開始切換到磁盤上。更多詳情,請參考SSIS性能計數器二三事。函數
2.根據資源使用的狀況規劃容量工具
SSIS的設計目標是在內存中高速逐行處理大量數據。所以,理解資源使用狀況是很是重要的,好比CPU,內存,I/O,以及網絡消耗。性能
CPU限制測試
當SSIS正在運行的時候,請設法搞清楚SSIS用了多少CPU,SQL Server總共用了多少CPU。若是SQL Server和SSIS安裝在同一臺機器上,那麼後者就顯得十分重要。由於一旦二者之間存在資源競爭,SQL Server每每會勝出——這會致使SSIS的數據轉換操做溢出到磁盤上,而這會下降數據轉換性能。
你感興趣的性能計數器應該是Process / % Processor Time (Total)。衡量sqlservr.exe和dtexec.exe的這個計數器值。若是SSIS沒法驅使CPU達到100%負載,這可能代表:
- 應用程序競爭:例如,SQL Server佔用了更多CPU資源,使CPU不能爲SSIS所用。
- 硬件競爭:一個常見的場景是你的磁盤I/O不夠好或者沒有足夠的內存,沒法應付要處理的數據量。
- 設計上的限制:你的SSIS包沒有利用到並行設計,而且/或者包使用了太多單線程任務。
網絡限制
SSIS會盡你網絡所能地傳輸數據。所以,搞清楚你的網絡拓撲結構是很重要的,一樣重要的是確保從源到目標之間的路徑具備低延遲和高吞吐。
如下性能計數器能夠幫你調整你的網絡拓撲結構:
- Network Interface / Current Bandwidth: 這個計數器會估算當前帶寬。
- Network Interface / Bytes Total / sec:這是每一個網絡適配器上發送和接收的字節數。
- Network Interface / Transfers / sec:顯示每秒發生多少網絡傳輸操做。若是這個值接近每秒40000IO,那麼請考慮增長網卡並在網卡間使用teaming技術。
這些計數器可讓你分析你的系統是否充分利用帶寬。理解這點可讓你經過使用千兆網卡,增長網卡數量,或者新增網絡地址以恰當地規劃網絡容量。
I/O限制
若是你能確保SSIS已經最小化磁盤寫入操做,SSIS只會在從源讀取數據以及寫入數據時接觸到磁盤。而若是你的I/O性能太慢,讀寫(特別是寫入)操做將成爲性能瓶頸。
因爲優化I/O超出了本文的範疇,請參考前期部署最佳實踐。請注意,I/O系統的規格不僅有它的大小(例如「我須要10TB」)——也包括了它的速度(例如「我須要達到每秒20000IO」)。
內存限制
你須要搞清楚一個很重要的問題「個人包到底須要多少內存?」
對此,關鍵的性能計數器有:
- Process / Private Bytes (DTEXEC.exe):當前SSIS使用的內存大小。這部份內存不能與其它進程共享。
- Process / Working Set (DTEXEC.exe):SSIS分配的總內存大小。
- SQL Server: Memory Manager / Total Server Memory:SQL Server分配的總內存大小。因爲SQL Server能夠經過AWE API分配內存,只有這個性能計數器能夠準確反映SQL Server使用的內存大小。要更好地理解SQL Server內存分配機制,請參考Slava Ok的博客。
- Memory / Page Reads / sec:這表明系統的內存壓力。若是這個指標持續在500以上,說明系統存在內存壓力。
3.源系統抽取速度基線
你得搞清楚從源系統抽取數據的速度。畢竟,SSIS不可能優化得比源系統還快——好比說,你不可能比讀取數據更快地進行數據轉換。
你能夠經過建立一個帶「Row Count」數據流組件的包來測量源系統的速度。
你能夠從命令行(DTEXEC)執行這個包並測量它的完成時間。也能夠用SSIS日誌輸出來準確計算執行時間。你須要的速度,就是每秒傳輸了多少行:
Rows / sec = Rows Count / Time
根據這個基準速度,咱們就知道能夠多快地從源抽取數據——這也是你轉換數據的速度極限。要計算出這個速度,你能夠嘗試如下方法:
- 升級驅動和驅動配置:針對網絡,數據源,和磁盤I/O,請確保你的驅動已經升級到最新版本。一般你的服務器默認網絡驅動並未針對網絡進行過精確的優化,當吞吐量大的時候這會致使性能降低。要注意的是,對於64位系統,你可能在設計時用的倒是32位的驅動。請確保在運行時你用的是64位驅動。
- 多重鏈接:爲了克服驅動的限制,你能夠嘗試利用多重鏈接從數據源抽取數據。正如數據源能夠處理併發鏈接同樣,同時進行多重抽取能夠提升吞量。若是併發致使了鎖定或者阻塞問題,能夠考慮分割數據源,並使你的包同時從多個分區抽取以分攤負載。
- 多網卡:若是網絡是性能性能瓶頸,而你已採用了千兆網卡和路由,那麼一個可能的解決方案就是在每一個服務器上都使用多塊網卡。要注意的是多網卡環境須要仔細配置,不然有可能會發生網絡衝突。
4.優化SQL Data Source,Lookup transformations,和Destination。
當你在SSIS中執行SQL語句(正如上圖所示的Data access mode對話框),是否在查詢數據源時實現Lookup邏輯,或者修改某些表,一些標準的優化手段能夠顯著地提升性能表現:
- 使用NOLOCK或者TABLOCK表提示以免鎖定開銷。
- 爲了優化內存消耗,只SELECT你確實須要的列。若是你SELECT一張表的全部列(例如,SELECT * FROM)你可能會浪費內存和帶寬以存儲和接收那些多餘的列。
- 儘可能在源數據庫或者目標數據庫進行時間日期類型的轉換,由於在SSIS實現的話成本過高。
- SQL Server 2008 Integration Servcies有個新功能Shared Lookup Cache。當用到並行數據管道時(參見下文第8點和第10點),這個功能能夠提供高速的共享緩存。
- 若是SSIS和SQL Server運行在同一臺服務器上,建議選擇SQL Server Destination而不是OLE DB Destination以提升性能。
- Commit Size爲0的話在堆上進行批量操做是最快的,由於只提交了一個事務。若是不能爲0,儘可能提升這個值以減小多批次寫入的開銷。將數據插入平衡樹結構時Commit Size爲0則不是個好主意——由於全部新進的行都必須一次性排序以插入目標平衡樹——而且若是你的內存有限,頗有可能溢出到硬盤上。將數據插入堆時Batch Size爲0是個比較理想的值。對於一個有索引的目標(表),我建議測試一下將Batch Size設在100000到1000000之間。
- 插入數據時將Commit Size設爲小於5000能夠避免鎖升級。要注意的是在SQL Server 2008如今你能夠在對象級別啓用/禁用鎖升級,不過要靈活調整這個設置。
- 對堆進行插入每每比彙集索引快。這意味着當目標表發生大量更改的時候你可能會刪除並重建索引,你能夠驗證一下保留索引和刪除並重建索引兩種方法的插入性能。
- 採用Partition和分區的SWITCH命令。例如,將數據載入只有單個分區的工做表,重建索引和約束後再將它SWITCH到主(目標)表。
- 請參考SQL性能團隊的另外一個建議用Lookup優化性能。
5.調整網絡
一個關鍵的屬性是鏈接的網絡包大小。默認狀況下這個值是4096字節。這意味着每4KB數據必須封裝爲一個新的網絡包。正如SqlConnection.PacketSize Property中所述在.Net Framework類庫中,增長網絡包大小能夠提升性能,由於傳輸大數據集的時候這意味着更少的網絡讀寫操做。
若是你的系統天生就是事務性的,有不少小數據量的讀/寫,那麼減少這個值會提升性能。
既然SSIS主要用於移動大量數據,你可能但願最小化網絡開銷。這意味着32767是最快的選項。也能夠在服務器層面用sp_configure配置網絡包大小,然而你不該該這麼作。將網絡包配置爲32767之外的值,DBA可能有他們的考慮。做爲替代方案,你能夠在Connection Manager裏以下覆蓋服務器設置。
另外一個網絡優化技巧是在操做系統層面採用Network Affinity。在高吞量的狀況下,有時你能夠經過這個辦法提升性能。
單從網絡來看,你可能須要與你的網絡管理員協做啓用Jumbo Frames(巨型幀)以便將幀負載能力從1500字節提升到9000字節。採用這種方法,將極大地減小移動大數據集所需的網絡操做。
6.數據類型——沒錯,回到數據類型!——理性點。
在本文的10點建議中,這多是最顯而易見的。然而,這是如此重要因此須要專門做爲一點建議。請遵循如下準則:
- 使數據類型儘量小以節約內存。
- 切勿執行代價高昂的類型轉換——這隻會下降性能。匹配源和目標的數據類型並顯式指定必要的類型轉換。
- 當你用到money,float,或者decimal類型時留意精度問題。同時,要注意money比decimal更快,並且在精度方面money也比float更讓人放心。
7.改變設計
SSIS比較擅長一些事情,而其它事情用別的工具更方便。你必須基於效率和對問題的瞭解來選擇ETL工具。爲輔助你的選擇,請注意如下幾點:
- 除非必要,不然切勿在SSIS中排序。爲了進行排序,SSIS會分配足以容納整個(須要移動的)數據集大小的內存。請儘可能在數據進入數據流以前就提早排好序。相對於在SSIS中排序,不如用帶ORDER BY子句的SQL語句去排序大型數據集——而後將Data Source的輸出標記爲Sorted(有序)便可。
- 有些時候用T-SQL操做會比在SSIS中處理數據更快。做爲通常性原則,任何基於集合的操做在T-SQL中老是比較快,由於問題能夠轉化爲SQL Server擅長解決的關係代數函數。而且,SQL Server查詢優化器對基於集合的操做自動採用了高並行處理和內存管理機制——在SSIS中你須要手工去實現。典型的集合操做包括:
- 基於集合的UPDATE語句——比逐行處理的OLE DB調用更高效。
- 像GROUP BY和SUM這樣的聚合計算。這用T-SQL計算一般會比SSIS在內存中的計算更快。
- 分支檢測是一種更改已有行而不是刷新整張表的技巧。爲實現分支檢測,你能夠採用更改檢測機制,例如SQL Server 2008的Change Data Capture(CDC)功能。若是沒法採用這樣的功能,你不得不比對源數據與目標數據以實現分支檢測。這多是個代價高昂的操做,須要維護特定的索引並計算校驗和。一般,刷新整張表會比較快。一個經驗是一旦某個表超過10%的行須要更改,那麼一般簡單地刷新這張表會比實現分支檢測更快。
8.分割問題
可伸縮計算的一個原則就是分而治之。這使你能夠更容易地處理問題的規模,利用並行處理以更快地解決問題。
對ETL設計來講,你可能會將源數據分割成大小相同的小數據塊。這一點很重要,由於若是你的數據塊大小有差別,最後你總得等待某個進程完成。好比說,以下圖,當4個進程分別運行在大小相同的數據塊,4個進程會同時完成2008年1月份數據的處理並開始處理2008年2月份的數據。但對於大小有差別的分割方式,前面的3個進程將同時完成數據處理而後等待第4個進程,這得花費更多時間。總的運行時間將取決於最大的數據塊。
爲建立相同大小的分區範圍,能夠考慮用時間區間和/或其它維度(例如地理信息)做爲分割機制。若是你的主鍵是個自增列或者其它自增值,你能夠用餘函數。若是你沒有比較合適的列用於分區,能夠爲每一行計算一個哈希值而後基於這個哈希值進行分區。
一些關於分區的提示:
- 在目標表應用分區。這樣你能夠並行地運行一個包的多個版本,以便將數據插入同一張表的不一樣分區。用了分區,SWITH就是你的好朋友。它不只增高並行載入的速度,也使你能夠更快地傳輸數據。請參考SQL Server在線文檔使用分區切換高效傳輸數據。
- 如上文所暗示的,你的包須要接受一個參數以指定它要抽取哪一個分區。這樣一來,你能夠以不一樣的參數同時並行執行同一個包,那麼你能夠從並行執行中得到更快的速度。
- 從命令行,你能夠用「START」命令屢次執行包。你能夠在SQL Server最佳實踐找到一個簡單的代碼示例。
9.最小化日誌操做
當你插入數據到SQL Server數據庫,儘可能最小化日誌操做。當數據插入到完整日誌模式的數據庫,因爲每一行都會先插入日誌,日誌會快速增加。
所以,設計SSIS包時,考慮如下幾點:
- 嘗試以批量模式而不是逐行模式執行數據流。經過批量導入模式,你能夠最小化插入日誌的操做。這個調整也能夠優化其它插入操做的底層磁盤I/O,並最小化日誌寫入形成的性能瓶頸。
- 若是你須要執行刪除操做,將你的數據構形成能夠TRUNCATE的形式而不是DELETE。後者會在日誌中爲刪除的每一行放一條記錄。而前者會簡單地移除所有數據同時在日誌作很小的記錄代表TRUNCATE發生過。與通常的觀點相對地,TRUNCATE語句能夠包含在事務中。
- 利用SWITCH和分區。若是分區須要被移除,你能夠用SWITCH語句(移入一個新分區或者移除最老的分區),這也是最小化日誌操做的語句。
- 使用DML語句的時候要謹慎,若是你將DML語句混在INSERT語句中,沒法最小化日誌操做。
10.正確地計劃與分發
當你的問題被分割成大小可控的數據塊以後,你得考慮一下何時以及在哪裏抽取這些數據塊。這是爲了不一個長時間運行的任務影響ETL數據流的總運行時間。
解決執行順序的一個好辦法就是建立一個優先級隊列而後執行一個包的多個實例(分別帶有不一樣的參數)。這個隊列甚至能夠簡單到就是SQL Server的一張表。每一個包都得在控制流包含一個循環模板:
1. 從隊列中找出一個要抽取的數據塊:
- 這意味着這個數據塊尚未抽取,而且它依賴的數據塊都已經抽取了。
- 若是隊列沒有返回任何項,退出包的執行。
2. 執行這個數據塊所需的操做。
3. 在隊列中將數據塊標記爲「已抽取」。
4. 返回循環的起點。
從隊列中提取一個數據塊並標記爲「已抽取」(上面的第一和第三步)能夠實現爲存儲過程。
這個隊列扮演了一個控制中心的角色並起到協調的做用,它能夠判斷執行順序並確保任意兩個包不會工做在相同的數據塊上。一旦這個隊列就緒,你能夠簡單地啓動多個DTEXEC副本以提升並行度。
點擊加入SQL Server精英羣
點擊訪問軟件技術諮詢中心