1. 程式人生 > >SSIS最佳實踐:SQL Server提升執行效能

SSIS最佳實踐:SQL Server提升執行效能

SQL Server整合服務(SQL Server Integration Services,SSIS)在其前輩DTS(Data Transformation Services,資料轉換服務)的基礎上進步了不少,從可用性、效能和並行等方面來說,它已經成長為一個企業級ETL(Extraction, Transformation and Loading,抽取、轉換和載入)產品,除了是一個ETL產品外,它也提供了各種內建任務來管理SQL Server例項。雖然SSIS的內部架構已經被設計為提供極好的效能和並行處理能力,但如果遵循最佳實踐,其效能還可進一步優化,在本系列文章中,我將討論SSIS的最佳實踐,我會將我過去幾年學習和使用SSIS的經驗與大家分享。

正如上面所說的,SSIS是DTS(SQL Server 7/2000)的替代產品,如果你曾經使用過DTS,你會發現SSIS包和DTS包非常類似,但本質上已經發生了很大的變化,SSIS不是DTS的增強版本,而是從零開始構建的一個新產品,與DTS相比,SSIS提供了更好的效能和並行處理能力,並克服了DTS的許多限制。

SSIS 2008進一步增強了內部資料流管道引擎,提供了更好的效能,你可能已經看到了SSIS 2008創造的一個ETL世界記錄,那就是在半小時內載入1TB資料。

SSIS的最大好處是它是SQL Server的一個元件,它可以隨SQL Server安裝而免費獲得,不再需要為它購買額外的許可,BI開發人員、資料庫開發人員和DBA都可以使用它轉換資料。

最佳實踐1:抽取大批量資料

最近我們從一個有3億條記錄的大表中抽取資料,起初,當SSIS包啟動時一切正常,資料如預期的那樣在轉換,但效能開始逐漸下降,資料轉換速率直線下降。通過分析,我們發現目標表有一個主聚集鍵和兩個非聚集鍵,因為大量資料插入這個表,導致其索引碎片水平達到了85%-90%。我們使用索引線上重建特性重建/重組索引,但在載入期間,每過15-20分鐘,索引碎片水平又回到90%,最終資料轉換和並行執行的線上索引重建過程花了12-13個小時,遠遠超出了我們的預期。

我們想出了一個辦法,當轉換開始前,我們將目標表的索引全部刪掉,轉換結束後又再重新建立索引,通過這樣處理後,整個轉換過程花了3-4小時,完全符合我們的預期。

整個過程我畫在下面的圖中了。因此我建議如果可能,在插入資料前,刪掉目標表上的所有索引,特別是插入大資料量時。

SQL Server SSIS最佳實踐:提升執行效能
在這裡插入圖片描述

轉換資料前,刪除目標表上的所有索引,轉換完後,再重建索引

最佳實踐2:避免使用select *

SSIS的資料流任務(Data Flow Task,DFT)使用一個緩衝區作為資料傳輸和轉換的中轉站,當資料從源表傳輸到目標表時,資料首先進入緩衝區,資料轉換是在緩衝區中完成的,轉換完畢後才會寫入到目標表中。

緩衝區的大小受伺服器硬體本身限制,它要估算行的大小,行大小是通過一行中所有列大小的最大值求和得出的,因此列數越多,意味著進入緩衝區的行就會越少,對緩衝區的需求就會越多,效能就會下降。因此轉換時最好明確指定需要轉換到目標表的列。即使你需要源表中的所有列,你也應該在select語句中明確指定列的名稱,如果你使用select *,它會繞到源表收集列的元資料,SQL語句執行時間自然就會長一些。

如果你將目標表不需要的列也做了轉換,SSIS將會彈出警告提示資訊,如:

[SSIS.Pipeline] Warning: The output column "SalariedFlag" (64) on output "OLE DB Source Output" (11) and component "OLE DB Source" (1) is not subsequently used in the Data Flow task. 
  Removing this unused output column can increase Data Flow task performance. 
  [SSIS.Pipeline] Warning: The output column "CurrentFlag" (73) on output "OLE DB Source Output" (11) and component "OLE DB Source" (1) is not subsequently used in the Data Flow task. 
  Removing this unused output column can increase Data Flow task performance.

當你在OLEDB源中使用“表或檢視”或“來自變數的表名或檢視名”資料訪問模式時要小心,它的行為和select *一樣,都會將所有列進行轉換,當你確實需要將源表中的所有列全部轉換到目標表中時,你可以使用這種方法。

最佳實踐3:OLEDB目標設定的影響

下面是一組會影響資料轉換效能的OLEDB目標設定:

資料訪問模式:這個設定提供“快速載入”選項,它使用BULK INSERT語句將資料寫入目標表中,而不是簡單地使用INSERT語句(每次插入一行),因此,除非你有特殊需求,否則不要更改這個快速載入預設選項。

保持一致性:預設設定是不會檢查的,這意味著目標表(如果它有一個標識列)將會建立自己的標識值,如果你檢查這個設定,資料流引擎將會確保源標識值受到保護,會向目標表插入相同的值。

保持空值:預設設定也是不會檢查的,這意味著來自源表中的空值將會插入到目標表中。

表鎖:預設設定是要檢查的,建議保持預設設定,除非是同一時刻還有其它程序使用同一個表,指定一個表鎖將會取得整個表的訪問權,而不是表中多行的訪問權,這很可能會引發連鎖反應。

檢查約束:預設設定是要檢查的,如果你能確保寫入的資料不會違反目標表上的約束,建議不要檢查,這個設定會指定資料流管道引擎驗證寫入到目標表的資料,如果不檢查約束,效能會有很大提升,因為省去了檢查的開銷。

最佳實踐4:每批插入的行數以及最大插入大小設定的影響

每批插入的行數:這個設定的預設值是-1,意味著每個輸入行都被看做是一個批次,你可以改變這個預設行為,將所有行分成多個批次插入,值只允許正整數,它指定每一批次包含的最大行數。

最大插入提交大小:這個設定的預設值是“2147483647”,它指定一次提交的最大行數,你可以修改這個值,注意,如果這個值設得太小,會導致提交次數增加,但這樣會釋放事務日誌和tempdb的壓力,因為大批量插入資料時,對事務日誌和tempdb的壓力是非常大的。

上面兩個設定對於理解改善tempdb和事務日誌的效能是非常重要的,例如,如果你保持最大插入提交大小的預設值,在抽取期間事務日誌和tempdb會不斷變大,如果你傳輸大批量資料,記憶體很快就會消耗光,抽取就會失敗,因此最好基於你自身的環境為其設定一個合理的值。

注意: 上面的建議得益於我多年的DTS和SSIS使用經驗,但如前所示,還有其它因素影響效能,如基礎設施和網路環境,因此,當你將這些措施推向生產環境之前,最好做一次徹底的測試。

最佳實踐5:SQL Server目標介面卡

如果你的目標是本地資料庫,建議你使用SQL Server目標介面卡,它提供了與Bulk Insert任務類似的資料插入效能,並提供了某些額外增強。使用SQL Server目標介面卡,在寫入目標表之前你可以對資料做轉換操作,但Bulk Insert任務是不行的,除了OLEDB目標介面卡可用的選項外,SQL Server目標介面卡還有更多選項,如圖1所示。例如,你可以指定是否觸發目標表上的插入觸發器,預設情況下,這個選項設定為“false”,意味著不會觸發目標表上的觸發器,如果啟用觸發器,將會引起效能下降,但為了強制實施資料和業務規則,觸發器是不可避免的。另外還有選項可以指定第一次和最後一次載入的數量,指定錯誤的最大數量,以及指定插入列的順序。

SQL Server的SSIS最佳實踐:優化資料表
在這裡插入圖片描述
圖1 SQL Server目標介面卡選項

SQL Server的SSIS最佳實踐:優化資料表
在這裡插入圖片描述
圖2 OLEDB目標介面卡選項
在這裡插入圖片描述
  如果你的SQL Server資料庫在遠端伺服器上,就不能使用SQL Server目標介面卡,這個時候只能使用OLEDB目標介面卡。此外,如果目標資料庫可能會從本地改為遠端,或從一個數據庫例項改為另一個數據庫例項,也最好使用OLEDB目標介面卡,以減小未來可能的改變。

最佳實踐6:儘可能避免非同步轉換

在討論不同種類的轉換對效能的影響之前,我們首先簡要地回顧一下SSIS的工作原理,SSIS執行時引擎執行包,當SSIS執行時引擎遇到資料流任務時,它會將資料流任務交給資料流管道引擎,資料流管道引擎會將資料流任務拆分成多個執行樹,可能會同時執行兩個或多個執行樹以提高併發處理能力和效能。你可能還不知道什麼是執行樹,下面就是答案。

正如其名,執行樹與樹的結構類似,每個執行樹有一套緩衝區,其範圍與執行樹緊密相關,每個執行樹也分配有一個作業系統執行緒,與緩衝區不同,執行緒可能與其它執行樹是共享的,即一個執行緒可以執行一個或多個執行樹。在SSIS 2008中,將資料流任務拆分成執行樹的程序已經得到了極大的增強,它可以建立一個執行路徑和子路徑,以便你的包可以利用高階多處理器系統。

同步轉換獲得一個記錄,經過處理,然後將其傳給其它轉換程序或下一個目標,記錄的處理不依賴於其它傳入的行,因為同步轉換輸出的記錄數和輸入的記錄數是相同的,它不需要新的緩衝區(處理是在相同的入站緩衝區中完成的),因為就這樣已經很快了。例如,在Derived列轉換過程中,在每個入站行增加一列,但不會增加輸出的記錄數。

與同步轉換有點不一樣,非同步轉換輸出的記錄數和輸入的記錄數可能不一樣,需要建立新的緩衝區,因為一個輸出依賴於一條或多條記錄,也被稱作阻塞轉換。例如,排序轉換就是一個不折不扣的阻塞轉換,它要求所有入站的行在處理之前必須抵達才行。

正如上面所討論的,非同步轉換需要額外的緩衝區用於輸出,不會重複利用入站輸入緩衝區,在處理之前它也會等待所有的入站行抵達,這也是非同步轉換執行得慢的原因,因此要儘可能避免這種情況。例如,如果不是有排序轉換,你可以ORDER BY子句從源表本身獲得已經排好序的結果。

最佳實踐7:DefaultBufferMaxSize和DefaultBufferMaxRows

正如我在最佳實踐六中談到的,執行樹為入站資料排序和執行轉換建立一個緩衝區,那麼要建立多大的緩衝區合適呢?單個緩衝區有多少行資料進入呢?它對效能有何影響呢?

緩衝區的大小依賴於有多少行資料進入緩衝區,有多少行資料進入緩衝區又依賴於其它一些因素。首先要考慮的是評估每一行的大小,它等於所有入站行包含的所有列的最大大小,其次要考慮的是資料流任務的DefaultBufferMaxSize屬性,它指定了一個緩衝區的預設最大大小,預設值是10MB,它的上下限是由SSIS的兩個內部屬性限制的,分別是MaxBufferSize(100MB)和MinBufferSize(64KB),意味著一個緩衝區的大小範圍是64KB到100MB,第三個因素是DefaultBufferMaxRows,它也是資料流任務的一個屬性,它指定了進入緩衝區的預設行數,預設值是10000。

雖然SSIS提供了這麼多的屬性可以設定一個合適的緩衝區大小,如果大小超出了DefaultBufferMaxSize的值,它會減少進入緩衝區的記錄行數。為了提高緩衝區的效能,你可以做兩件事情,首先從源中移除不需要的列,併為每一列設定正確的資料型別,特別是你的源是一個平面檔案時,這樣可以讓緩衝區儘可能容納更多的記錄行,其次,如果你的系統有充足的記憶體,你可以通過調整這些屬性,最後建立少量的大緩衝區,這樣會提升效能。注意,如果你將這些屬性的值修改到某個分頁開始的臨界值,會對效能產生不利的影響,因此在設定這些屬性之前,首先應在你的環境進行全面的測試,最終找到一個合適的值。

你可以開啟BufferSizeTuning事件的日誌,這樣就可以看到進入緩衝區的行數,你也可以監視“Buffers spooled”效能計數器檢視SSIS是否開始了分頁。

最佳實踐8:BufferTempStoragePath和BLOBTempStoragePath

如果記憶體資源不夠,Windows會觸發一個記憶體過低的通知事件,記憶體溢位、記憶體壓力、輸入記錄,除了BLOB,SSIS會將它們輸出到檔案系統,檔案系統的位置就是由資料流任務的BufferTempStoragePath屬性設定的,預設是空的,在這種情況下,輸出位置基於TEMP/TMP系統變數指定的位置。

同樣,SSIS在將BLOB資料發到目標之前,可能會將其先寫入到檔案系統,因為BLOB資料通常非常大,SSIS緩衝區中儲存不下,輸出的位置是有資料流任務的BLOBTempStoragePath屬性設定的,預設是空的,在這種情況下,輸出位置也是基於TEMP/TMP系統變數的,如果你不為這些屬性指定具體的值,TEMP和TMP系統變數的值將會被當做輸出的目標,如果你開啟了資料流任務PipelineInitialization事件的日誌,相同的資訊會被記錄到日誌檔案中,如:

User:PipelineInitialization,ARSHADALI-LAP,FAREAST\arali,Data Flow Task,{C80814F8-51A4-4149-8141-D840C9A81EE7},{D1496B27-9FC7-4760-821E-80285C33E74D},10/11/2009 1:38:10 AM,10/11/2009 1:38:10 AM,0,0x,No temporary BLOB data storage locations were provided. The buffer manager will consider the directories in the TEMP and TMP environment variables.

現在最重要的就是改變BufferTempStoragePath和BLOBTempStoragePath的預設值,最好是將它們設為不同的磁碟路徑,這樣可以提高I/O效率,從而提升整體效能。

最佳實踐9:好好利用DelayValidation屬性

SSIS使用驗證確定包在執行時是否會失敗,它使用兩種型別的驗證,第一種是包驗證,在開始執行包之前,驗證包及其包含的所有元件,第二種是元件驗證,一開始就驗證包中的所有元件。

我們假設一個場景,包中的第一個元件建立一個物件,如一個臨時表,包中的第二個元件將引用這個臨時表,在包的驗證過程中,第一個元件還沒來得及執行,因此臨時表也還沒建立好,在驗證第二個元件時最終導致包驗證失敗。SSIS會丟擲一個驗證異常,並不會啟動包的執行,那麼你將如何處置這種場景中的包?

為了解決這種場景存在的問題,每個元件都有一個DelayValidation屬性,預設值為“flase”,如果你將其設為“true”,所有驗證都會忽略,在包執行過程中,只會在元件級驗證元件。

最佳實踐10:使用並行執行提升效能

通過並行執行包和資料流任務,SSIS實現了較好的效能,SSIS包和資料流任務的並行執行可以由SSIS的兩個屬性進行控制。

MaxConcurrentExecutables:它指定一個包內的最大並行執行數(包內不同的任務),即SSIS執行引擎可以建立的執行緒數量,如果你的包制定的是連續工作流,這些屬性不會有任何差異,但如果你的包制定了並行任務,這個屬性就需要改變,其預設值是-1,表示所有可用的處理器數+2,如果你的處理器支援超執行緒,那它就是所有邏輯處理器的數量+2。

EngineThreads:MaxConcurrentExecutables是SSIS執行時引擎並行執行時使用的屬性,EngineThreads是資料管道引擎使用的屬性,在SSIS 2005中預設值是5,在SSIS 2008中預設值是10,這個屬性指定源執行緒(從源抽取資料)和工作執行緒(執行資料轉換和載入)的數量,這些執行緒是由資料流管道引擎建立的,管理資料流任務中資料的傳輸和轉換。如果EngineThreads的值為5,表示最大可以建立5個源執行緒和5個工作執行緒。注意,這個屬性僅僅是給資料流管道引擎的一個建議,管道引擎可以視需求建立更多或更少的執行緒。

假設你有一個包,它有5個並行資料流任務,MaxConcurrentExecutables屬性的值為3,當你開始執行這個包時,執行時將會並行啟動3個數據流任務,任何資料流任務執行完時,下一個等待的資料流任務就會啟動,以此類推,此時在資料流任務內發生的事情是由EngineThreads屬性控制的。在最佳實踐6中我已經談到,一個數據流任務會被拆分成多個執行樹,資料流管道引擎會建立源和工作執行緒,它們的數量等於EngineThreads屬性的值,也就是可以並行執行的執行樹的數量。如果你將EngineThreads的值設為5,那麼你的資料流任務就會被拆分成5個執行樹,但並不意味著所有執行樹會並行執行。

在修改這些屬性時一定要非常小心,在應用到生產環境之前進行徹底的測試是必要的,因為如何正確配置了這些屬性,在系統有限的資源限制下,通過並行執行可以提高效能,但如果配置不當,也會損害效能,因為從一個執行緒到另一個執行緒存在太多的上下文切換,建議建立並行執行的執行緒數量不要超過可用的處理器數量。

最佳實踐11:什麼時候使用時間日誌,什麼時候應該避免使用事件日誌

日誌時診斷執行期間發生的問題的最佳方法,當你的程式碼沒有按預期執行時,它可以幫上大忙。現在,幾乎所有的程式語言都提供了日誌機制,通過日誌確定異常問題或執行失敗的根本原因。SSIS允許你開啟日誌功能,它允許你選擇不同的事件和元件記錄日誌,並且可以指定日誌的存放位置。

雖然日誌可以幫你確定問題的根本原因,但它會引起效能下降,特別是如果過度使用日誌,效能下降會更明顯,因此我建議你僅當必要時才開啟日誌功能,你可以動態設定LoggingMode屬性的值來啟用或禁用日誌功能,當你懷疑某個包有問題時,你可以開啟日誌功能,並選中合適的事件進行記錄。

最佳實踐12:使用效能計數器監控SSIS效能

除了日誌可以進行效能診斷外,SSIS還引入了效能計數器來監控SSIS執行時和資料流管道引擎的效能。例如,SSIS包例項計數器表示執行在系統上的SSIS包數量,行讀取和行寫入計數器分別表示來自源的總行數和寫入到目標的總行數,緩衝區使用和緩衝區記憶體計數器分別表示建立的總緩衝區數量和緩衝區使用的記憶體大小,緩衝區輸出是一個非常重要的計數器,表示當實體記憶體不足時寫入到磁碟的緩衝區數量,BLOB位元組讀、BLOB位元組寫和BLOB檔案使用計數器分別表示BLOB資料傳輸時BLOB位元組讀、寫和資料流引擎目前在使用的用於輸出BLOB資料的檔案的數量。

如果你從安裝有SQL Server和SSIS的Windows Server 2003升級到Windows Server 2008,SSIS效能計數器將會消失,因為升級過程移除了這些效能計數器,如果想找回這些效能計數器,請參考這篇知識庫文章(http://support.microsoft.com/kb/955632)。

最佳實踐13:SSIS中的分散式事務及其影響

SSIS允許你將多個可執行程式組合到一起,然後通過分散式事務在一個事務中執行,你需要啟動Windows服務中的分散式事務協調處理器服務,起初一聽起來感覺很酷,但它可能會有阻塞問題,特別是當某個任務的執行週期很長時,很容易發生阻塞。例如,假設在佇列中你有一組資料流任務,一個Web Service任務,然後又是一個數據流任務,第一個資料流任務從源抽取資料,需要幾分鐘時間,Web Service任務從一個Web Service抽取資料,需要花幾個小時,最後的資料流任務合併這些資料,並將它們上載到最終表中。現在如果你在一個事務中執行這三個任務,資源將會被第一個任務鎖定,直到其結束,即使它不需要Web Service任務執行需要的資源。

因此即使SSIS提供了分散式事務的功能,但也應該謹慎使用,即使你真要使用它,也要及時將任務清除出組,並要謹慎設定IsolationLevel屬性。我的建議是儘可能避免使用這個特性,轉而尋求其他替代解決方案。

最佳實踐14:檢查點特性如何幫助包重啟

SSIS有一個很酷的新特性叫做檢查點(Checkpoint),它允許你的包在下次執行時,從上次失敗的地方開始啟動,這樣可以節省不少執行時間。你可以通過設定包的三個屬性(CheckpointFileName,CheckpointUsage 和 SaveCheckpoints)開啟用這個新特性,除此之外,你還需要將所有需要重啟任務的FailPackageOnFailure屬性設為True,設定了這個屬性後,執行失敗時會將相關資訊捕獲到檢查點檔案中,下次執行時就從上次失敗的地方開始執行起走。

那它是如何工作的呢?當你為某個包啟用檢查點屬性後,執行狀態會寫入到檢查點檔案中,這個檔案的名字和位置是通過CheckpointFileName屬性指定的。下一次執行時,執行時引擎會參考檢查點檔案,在重新執行包之前,先檢視最後一次執行的狀態,如果它發現最後一次執行的狀態為失敗,它就知道最後一次失敗的地方,然後就從那個地方重新開始執行。如果在下一次執行前你刪除了這個檔案,包將會從頭開始執行。

啟用這個特性後,在下一次執行時,你可以節省大量的時間,因為它會跳過執行成功的步驟。這裡需要注意的是,你可以讓一個任務加入檢查點,包括資料流任務,但它不能應用到資料流任務內,即你只能在資料流任務級別啟用它,不能在資料流任務內部使用檢查點。假設你有一個數據流任務,並將FailPackageOnFailure屬性設為True讓其加入檢查點,現在在資料流任務內,你有5個連續轉換,前四個都執行成功了,在第五個時執行失敗了,在下一次執行時,還是會從第一個轉換開始執行,前四個轉換會再執行一次。

此文轉至:http://www.ithov.com/server/94832.shtml