2008-08-23 53 views
52

我遇到了一些性能瓶頸,我的C#客戶端將批量數據插入到SQL Server 2005數據庫中,我正在尋找方法加快這一進程。在SQL Server中批量插入大量數據的最快方法是什麼(C#客戶端)

我已經在使用SqlClient.SqlBulkCopy(基於TDS)來加速跨線的數據傳輸,這有助於很多,但我仍然在尋找更多。

我有一個簡單的表看起來像這樣:

CREATE TABLE [BulkData](
[ContainerId] [int] NOT NULL, 
[BinId] [smallint] NOT NULL, 
[Sequence] [smallint] NOT NULL, 
[ItemId] [int] NOT NULL, 
[Left] [smallint] NOT NULL, 
[Top] [smallint] NOT NULL, 
[Right] [smallint] NOT NULL, 
[Bottom] [smallint] NOT NULL, 
CONSTRAINT [PKBulkData] PRIMARY KEY CLUSTERED 
(
    [ContainerIdId] ASC, 
    [BinId] ASC, 
    [Sequence] ASC 
)) 

我在平均約爲300行,其中數據筒和BinId是在每個塊和序列值恆定塊插入數據0-n的並根據主鍵對值進行預先排序。

%磁盤時間性能計數器花了很多時間在100%,所以很明顯磁盤IO是主要問題,但我得到的速度比原始文件副本低幾個數量級。

它是否幫助任何如果我:

  1. 刪除主鍵,而我做的插入,並重新創建後
  2. 執行插入到一個臨時表具有相同的架構,並定期將其轉移到主表保持插入正在發生的表的大小小
  3. 還有其他嗎?

- 根據我得到的答覆,讓我澄清一點:

波特曼:我使用了一個聚集索引,因爲當數據被所有進口我需要訪問數據按順序依次進行。在導入數據時,我並不特別需要索引。在執行插入操作時使用非聚集PK索引有什麼好處,而不是完全放棄導入的約束? Chopeen:數據正在許多其他機器上遠程生成(我的SQL服務器目前只能處理大約10個數據,但我希望能夠添加更多數據)。在本地機器上運行整個過程是不實際的,因爲它將不得不處理50倍的輸入數據來生成輸出。

Jason:我沒有在導入過程中對錶進行任何併發查詢,我會嘗試刪除主鍵,看看是否有幫助。

+0

http://msdn.microsoft.com/en-us/library/ms174335.aspx – JohnB 2010-05-24 18:59:09

回答

0

是的,你的想法會有所幫助。
如果在加載時沒有發生讀取,則依靠選項1。
如果在處理過程中正在查詢目標表,則依靠選項2。

@Andrew
問題。你以300的塊插入。你插入的總量是多少? SQL服務器應該能夠快速處理300個普通舊插入。

0

如果可能,增加分配給服務器的內存或服務器使用的緩衝區大小如何?

4

您是否嘗試過使用事務?

從你所描述的情況來看,讓服務器將100%的時間提交給磁盤,看起來你是在一個原子SQL語句中發送每行數據,從而迫使服務器向每一行提交(寫入磁盤)。

如果您使用的是交易,服務器將只在交易結束時提交一次

如需進一步的幫助:您使用什麼方法將數據插入服務器?使用DataAdapter更新DataTable,還是使用字符串執行每個句子?

+0

很慢半拍,但大家有沒有發現現在,這是一件好事。我正在使用來自客戶端應用程序的通用DbCommand代碼編寫插入過程,因此我無法使用SqlClient特定的東西或SQL Server批量工具 - 這個簡單的提示已將我的運行時間從一分半鐘減少到了5秒鐘。 – Whelkaholism 2013-04-25 09:28:25

18

您已經在使用SqlBulkCopy,這是一個好的開始。

但是,僅使用SqlBulkCopy類並不一定意味着SQL將執行批量複製。特別是,SQL Server執行高效批量插入時必須滿足一些要求。

延伸閱讀:

出於好奇,爲什麼你的指標集這樣呢?看起來像ContainerId/BinId/Sequence是很多更適合作爲非聚集索引。是否有特定原因希望將此索引聚類?

1

我認爲這聽起來像這樣可以使用SSIS packages完成。它們與SQL 2000的DTS包類似。我已經使用它們成功轉換了純文本CSV文件,現有SQL表格甚至是跨越多個工作表的6位行的XLS文件。您可以使用C#將數據轉換爲可導入的格式(CSV,XLS等),然後讓SQL服務器運行預定的SSIS作業來導入數據。

創建SSIS包相當簡單,內置SQL Server企業管理器工具嚮導(標記爲「導入數據」,我認爲),在嚮導結尾處可以選擇將其保存爲一個SSIS包。還有一些更多信息on Technet

3

BCP - 這是一個痛苦的設置,但它已經存在,因爲數據庫的曙光,它非常快。

除非您按照該順序插入數據,否則3部分索引會真的放慢速度。稍後再應用它也會讓事情變得緩慢,但這將是第二步。

Sql中的複合鍵總是很慢,鍵越慢越慢。

8

我的猜測是,如果您將該索引更改爲非集羣,您會看到顯着的改進。這使你有兩個選擇:

  1. 更改索引非聚集,並把它作爲一個堆表,沒有聚集索引
  2. 更改索引非聚集,但然後添加一個代理鍵(如「ID 「),並使其成爲一種身份,主鍵,和聚簇索引

兩者將加快您插入沒有明顯放慢您的讀取。

想想這樣 - 現在,你告訴SQL做一個批量插入,但是你要求SQL爲每個添加任何東西的表重新排序整個表。使用非聚集索引,您將按照它們進入的順序添加記錄,然後構建一個單獨的索引,指示其所需的順序。

3

我不是一個聰明人,我沒有很多SqlClient.SqlBulkCopy方法的經驗,但這裏是我的2美分,它是值得的。我希望它能幫助你和其他人(或者至少讓人們喚起我的無知;)。

除非數據庫數據文件(mdf)與事務日誌文件(ldf)位於單獨的物理磁盤上,否則永遠不會匹配原始文件的複製速度。此外,任何聚簇索引還需要位於單獨的物理磁盤上以進行更公平的比較。

您的原始副本不記錄或維護用於索引目的的選擇字段(列)的排序順序。

我同意波特曼創建非集羣身份種子並將現有非集羣索引更改爲聚集索引。至於你在客戶端上使用什麼構造......(數據適配器,數據集,數據表等)。如果服務器上的磁盤IO爲100%,我認爲您最好花時間分析客戶端構造,因爲它們看起來比服務器當前處理的速度快。

如果按照波特曼關於最小記錄的聯繫,我也不會覺得周圍的交易批量複製將有很大的幫助,如果任何,但我已經在我的生活是錯誤的許多倍;)

此次榮獲」現在不一定能幫到你,但如果你弄清楚你目前的問題,這下一個評論可能會幫助解決下一個瓶頸(網絡吞吐量) - 尤其是當它通過互聯網...

Chopeen問了一個有趣的問題。你是如何確定使用300個記錄數塊來插入的? SQL Server有一個默認的數據包大小(我相信它是4096字節),這對我來說是有意義的,可以導出記錄的大小,並確保您有效地使用客戶端和服務器之間的數據包傳輸。 (請注意,您可以更改您的客戶端代碼上的數據包大小,而不是服務器選項,這顯然會改變它的所有服務器通信 - 可能不是一個好主意。)例如,如果您的記錄大小導致300個記錄批次需要4500字節,您將發送2個數據包,其中第二個數據包大部分被浪費。如果批量記錄計數是任意分配的,那麼做一些快速簡單的數學可能是有意義的。我可以告訴(並記住數據類型大小),每個記錄(如果int = 4字節和smallint = 2字節)恰好有20個字節。如果你正在使用300個記錄計數批次,那麼你試圖發送300×20 = 6000個字節(加上我猜測連接的一些開銷等)。以200個記錄計數批次發送(200 x 20 = 4,000 +空間用於開銷)= 1個數據包可能會更高效。然後再一次,你的瓶頸似乎仍然是服務器的磁盤io。

我知道你要比較相同的硬件/配置的原始數據傳輸到SqlBulkCopy的,但這裏的地方我會去還,如果面臨的挑戰是我的:

這個職位可能不會幫你了,因爲這是相當古老的,但我會問下你的磁盤的RAID配置是什麼和你使用的磁盤的速度?嘗試將日誌文件放置在數據文件上使用RAID 10(理想情況下爲1)的驅動器上。這可以幫助減少大量主軸移動到磁盤上的不同扇區,並導致更多的時間讀取/寫入,而不是非生產性的「移動」狀態。如果您已經將數據和日誌文件分開,是否將索引放在與數據文件不同的物理磁盤驅動器上(只能使用聚簇索引執行此操作)。這將不僅允許同時更新帶有數據插入的日誌信息,而且允許索引插入(以及任何昂貴的索引頁操作)同時發生。

18

這裏是你如何禁用/啓用在SQL Server索引:

--Disable Index ALTER INDEX [IX_Users_UserID] SalesDB.Users DISABLE 
GO 
--Enable Index ALTER INDEX [IX_Users_UserID] SalesDB.Users REBUILD

這裏有一些資源,幫助你找到一個解決方案:

Some bulk loading speed comparisons

Use SqlBulkCopy to Quickly Load Data from your Client to SQL Server

Optimizing Bulk Copy Performance

絕對看看NOCHECK和TABLOCK選項:

Table Hints (Transact-SQL)

INSERT (Transact-SQL)

+0

一些很好的信息,謝謝! – tbone 2010-12-14 15:57:31

相關問題