2012-06-20 53 views
0

TLDR版本: 批量插入會告訴你它影響了多少行。它不會告訴你試圖影響多少行,或者多少行失敗。這個問題很明顯,我想知道是否有更可靠的文本文件上傳方式,將代碼保存在服務器中。SQL Server 2008:是否有更好的(服務器端)替換大容量插入?

完整版本:我有一個應用程序需要定期將文本數據文件上傳到SQL Server表中。由於一些瘋狂和瘋狂的原因,我想把它放在一個存儲過程中,使它成爲抽象層的一部分,而不是讓前端應用程序直接寫入表中。

與大多數SQL服務器腳本我花了我平時的時間份額撲我的頭撞牆得到它在所有的工作。 (與本網站和其他搜索過去的職位不小的幫助。)

威爾批量插入讀標題行,以確定哪些字段寫?不,不得不使用格式文件(並希望表結構/順序不會改變),或者使用僅包含數據文件中的列的登臺表。臨時表在將數據複製到實際表之前接收數據。

如果您在目標表中忽略單列(即使是具有默認值的列)並且不使用格式文件,該怎麼辦?你會得到這樣的自我解釋錯誤信息「無法從OLE DB提供程序獲取一行」BULK「鏈接服務器」(null)「。」使用前面提到的登臺表,省略任何不在數據源中的列,可以解決這個問題。

這很好,我可以忍受這一點。這不是可怕的部分。這是。

如果臨時表中仍然有被定義爲NOT NULL任何字段,但一個數據源行是空該列,你不會得到一個錯誤。根據我的測試,如果你有(說)5行數據,第3行缺少NOT NULL字段中的數據,那麼你不會得到一個錯誤,但會得到消息「4行更新」。如果您需要5行並對受影響的行數進行交叉檢查,以確保預期的編號存在,但這些文件的長度各不相同,並且Bulk Insert不會告訴您它實際上讀了多少行。更糟糕的是,在某些情況下,一行中缺少的字段也會阻止上傳以下(有效)行。

顯而易見的解決方案?從登臺表中刪除NOT NULL約束,並處理登臺表和真實表之間的接口中的任何空例外。但是......我擔心的是,這件作品可能會在我還沒有遇到的其他情況下做同樣的事情。也就是說,讀一行,沒有將它寫入登臺表,並且不會拋出異常,這樣沒有人知道數據丟失,直到他們去查找並發現它不在那裏。即使Access有更好的文本導入選項。

我的問題,那麼,是...有沒有處理的變量行長度的文本文件上傳到SQL Server,而不必依賴於前端應用程序做一個更好的(更可靠)的方式?

在此先感謝您的任何建議。

+0

那麼,你正在嘗試做一個'BULK INSERT',它不應該讓你感到驚訝,因爲你沒有太多的控制它的方式。如果你想要更多的控制(例如使用SSIS中的數據流任務),你將會獲得性能上的提升,這真的取決於你 – Lamak

+0

這不是一個問題。這完全是一個「它有時不會這麼做的問題,更重要的是它不會告訴你它沒有這樣做」。 –

回答

1

傳送數據時臨時表.NET的SqlBulkCopy會給你更多的控制權,並仍然提供卓越的性能。

現在,考慮到你希望所有的服務器本身的邏輯,也許下面的策略可能爲你工作:

保留臨時表中,沒有任何形式的限制,可能使你的進程失敗。在其上創建其他列,如IsValid,另加一個ErrorMessage列。

然後寫一個存儲過程,將驗證各行上的數據,檢查條件,缺失值,文字的長度,任何自定義業務規則可能要強制執行。

每個驗證可以是單個UPDATE語句來臨時表,設定IsValidErrorCode加上ErrorMessage,具有在其WHERE子句條件,例如。

一旦所有驗證UPDATE語句已經運行,您應該有一個有效導入的行的子集(標記爲IsValid)和其他可以清楚地標識問題原因並記錄或通知用戶的其他行逐行依據。

這種策略在經常導入無效數據的場景下證明是非常有效的。

現在,如果您要並行運行多個導入進程,那麼您可能需要根據某個「進程標識符」將導入的數據劃分到登臺表中,並可能對其進行索引,以避免進程之間的鎖定在數據上運行批量驗證時。

+0

謝謝巴勃羅。你所描述的內容(在後面的部分)聽起來很像我在說當我正在查看「(處理)臨時表和實際表之間的接口中的任何空異常」時的想法。我主要關心的是在那之前;當然,刪除Not Nulls應該刪除任何有關丟失數據和無效數據類型的問題,我可以通過使所有字段處於Staging NVarChar中來擴展您的想法。儘管如此,我擔心的是這一步。我永遠無法100%確定所有行上傳。我也會看看SQLBulkCopy。再次感謝。 –

+1

我明白了。那麼,在這種情況下,SqlBulkCopy會給你的確定性。但是請注意,使用它進行錯誤處理是非常原始的。意思是,如果發生錯誤,該過程將失敗。 所以爲了防止你必須批量轉儲數據,比如1k或10k行,這取決於你的數據大小。當批處理失敗時,您可以單獨處理行,或者細分批處理類,例如二進制搜索錯誤,以及類似的事情。 這是主要問題。這些高性能特性主要是由於缺乏日誌記錄和驗證。 –

+0

例如,這裏試圖解決這個問題:http://www.codeproject.com/Articles/387465/Retrieving-failed-records-after-an-SqlBulkCopy-exc –

0

SqlBulkCopy類System.Data.Client應該給你更多的控制和反饋。

+0

謝謝羅伯特。巴勃羅打敗你,但正如我對他說過的那樣,我會看看那樣的情況,以防我必須爲此而去客戶端。 –

0

即使處理破損的文件仍然很難,我仍然會使用SSIS。它給你很多控制和良好的性能。

+0

感謝Cade,但其目的是確實有一個存儲過程,前端可以通過簡單地將文件名傳遞給它來調用。 (我可能沒有說清楚,對不起。)正如我在上面的評論中提到的,我並沒有太多的控制過程(我很高興能夠使用臨時表/更新主表的方法)這實際上只是一個可靠性問題。如果批量插入不關心它們,那麼數據行可以在沒有警告的情況下消失到以太網中,這一點讓我感到有些不安。 –

+0

@AlanK我想你可以批量插入一列varchar(max) - 然後處理...儘管這可能很有吸引力,但我仍然會親自看看SSIS(你可以從一個代理作業開始存儲過程),因爲它只是讓你加載更多的數據,因爲它是面向流的(你可能需要在純T-SQL中批量解析5m行文本行),它給了你很大的靈活性。我希望BULK INSERT有更多的選擇,但問題的一部分是SQL總是更加面向集合,並且很多ETL需要一些嚴重的非集合處理。 –

+0

嗯,代理工作從sproc。這是我一定會探討的。我還沒有花太多時間在SSIS上。再次感謝凱德。 –