【高級內部資料】.NET數據批量寫入性能分析 第二篇
在上一篇文章中,我們已經講述了一些鋪墊性的知識,那么從本篇開始,就開始正式的研究批量插入性能問題。
首先來看看,我們主要測試那些東西。因為我們本系列文章是研究SqlBulkCopy與SSIS的性能,所以,我們將他們進行詳細的對比。對於SqlBulkCopy,我們主要對它的一下幾個屬性感興趣,因為這些屬性對性能的影響很大:
Table locking:在進行批量插入數據的時候,往往會在要插入數據的表上創建一個排它鎖,一方面,這個鎖使得插入的更快;另一方面,也是的其他回話對此表的讀取等操作都進入等待。我們會使用很多不同的場景來測試這個屬性,讓大家有一個比較清晰的認識。
BatchSize:這個參數主要是定義了每次批量插入的數據條數。我們發現:沒有什么文檔來描述這個值對性能的影響,所以,我們也會研究這個屬性值。
Use Internal Transaction:其實,很多時候,很多人對SqlBulkCopy的事務都理解有誤。我們通過很多的測試和實踐發現,如果我們在SqlBulkCopy插入數據的時候,不用事務,速度將會非常的快,當然,這個快是犧牲其他的特性為代價的。
出了測試上面的一些屬性之外,我們還會測試與批量數據的導入相關的問題,如下:
- 我們可以將數據導入到含有聚集索引的表和堆表中,看看哪一種表的導入速度最快,也看看如何更好的導入數據。
- 看看在數據導入的時候,數據庫日志文件的使用情況。在使用批量導入數據的時候,不僅僅會寫數據文件,還會不斷的寫日志,我們可以看看不同的設置和方式導致日志的大小以及其他影響。
- 使用SQL Server Trace的Flag 610 標記可以在數據批量導入的時候使得日志記錄最小,這個Flag是否值得使用。
OK,下面我們就來准備測試環境。
首先,我們創建一個簡單的具有6個字段的表,如下:
很顯然,表中的每一行數據的大小大約是320字節。在測試的過程中,我們將會用不同的數據量來填充這個表,這個數據量會從60一直到6百萬,同時也看看相關性能的數據是否有一個線性的關系。
同時,也為了測試聚集索引表和堆表,我們也會在需要的時候創建索引,如下:
我們在每次測試一個場景的時候,都會將這個表從數據庫中銷毀,然后重建。我們插入表中的數據都是采用隨機生成的。另外,我們還會常見兩種基於隨機值的測試:
1. 每一個Producer(也就是數據生產者)產生的每一行數據的值都是相同的,每個字段的值肯定是隨機的。可能如下:
2. 每一個Producer產生的每一行數據值都完全不同,類似如下:
之所以要進行上面兩個測試,主要是要看看對於相同的數據的數據行在進行網絡輸入之前是否被壓縮了(因為相同的數據值多次重復的出現,這就是一個很好的壓縮的機會,可以大大的節省網絡帶寬,使得數據插入更快)。
另外,對於我們表所在的數據庫,就采用最簡單的日志模式,這也是絕大多數數據庫采用的方式。我們不會測試SqlBulkCopy的屬性與上面所有條件的所有組合,因為很多的組合的結果是可憑經驗推斷出來的,並且也不是所有的組合方式都對性能有影響。
為了使得測試更為的准確,在SqlBulkCopy進行數據的批量寫入之前,所有的數據producers都會先把數據全部准備好,之后,再將數據傳遞給SqlBulkCopy。我們關注的是SqlBulkCopy寫入性能,以及它對數據庫的影響,請記住這一點。
下面,我們就進入第一個場景:一個consumer(數據的消費者,在這里,這個數據消費者就是SqlBulkCopy)接受6百萬條數據,然后將數據導入到一個堆表中。
通過多次測試發現,consumer執行完成的時間是56秒,同時我們這里把Tablock和BatchSize的值設置為了0,同時我們發現日志文件增加了6M,如圖:
在此過程中,網絡的情況如下:
我們可以看看網絡的使用大約25%(測試用的是1GB的帶寬),也就說,沒有充分的利用帶寬。
另外,CPU也顯示了只有一個線程在運行,沒有完全的使用所有的核的功能。也就說,如果數據導入的客戶端有多個核,那么我們可以增加SqlBulkCopy的數量,采用並行技術來導入數據,從而提高性能。
下面,我們就來測試上面的想法,如下:
可以看到上面的圖,我們采用了4個SqlBulkCopy。
此時的網絡使用如下:
此時充分的利用了帶寬,並且速度也提升了300%。
今天就到這里,讓大家有一個感覺!下一篇,我們接着比較更多的東西