2015-12-11 26 views
2

在我的Web應用程序中,用戶可以一次插入大量數據,以提高性能我正在使用SqlBulkCopy類。它將多次運行插入兩個不同表中的單個操作。如果用戶取消操作或失敗,那麼我需要數據回滾,以便使用隔離級別快照將所有內容都包含在事務中。SqlBulkCopy在事務內部插入時阻止對錶的任何其他寫入

這是我的理解是,使用快照隔離將允許其他用戶同時寫入/讀取表。但是,當一個數據上傳正在發生時,它將阻止對該表的任何其他寫入,直到整個父事務完成。

下面是一些簡化的代碼,顯示了這個問題。我排除了很多功能,但是這個想法保持不變。我遍歷內存集合中的一些數量,將它們批量複製到一個表中,將它們退回,然後批量複製到另一個表中。

using (var transaction = myDbContext.Database.BeginTransaction(
System.Data.IsolationLevel.Snapshot)) 
{ 
    var myCollectionOfObjects; 

    while(!GetData(ref myCollectionOfObjects)) 
    {  

    SqlBulkCopy bulkCopy = new SqlBulkCopy(myCon, transaction); 

    //Sets the columns + rows 
    SetUp(bulkCopy); 

    bulkCopy.WriteToServer(); 
    //After the bulkcopy operation is complete 
    // we retrieve the rows inserted and do another bulk copy to a different table 

    var recentlyAddedRows = GetRecentlyAddedRow(); 

    SqlBulkCopy otherTableBulkCopy = new SqlBulkCopy(myCon, transaction); 


    SetUpBulkCopyForOtherTable(otherTableBulkCopy); 

    otherTableBulkCopy.WriteToServer();   
    } 
    transaction.Commit(); 
} 

所以,如果一個用戶當前本次交易中,即使是回滾,其他所有寫事務表將被封鎖,以便其他用戶在做同樣的功能或試圖寫入表會受阻。

這是預期的行爲,有沒有辦法解決這個問題?

編輯

通過觀察,由於導致的排他鎖(X)的bulkcopy類SQL應用鎖好像是被在那裏,如果你是將它們插入表對象上設置一次只有一個意圖鎖應用於表(IX)。仍然不確定是否有解決方法,但我認爲這是由於鎖升級。

更改表格索引上的允許頁面鎖定和更改批量副本的批量大小已在我的一些測試中獲得了完全鎖定,但它們很有氣質。

+0

您爲每個事務插入了多少行? – usr

+0

看看SqlBulkCopy的文檔,看起來你需要將事務傳遞給構造函數。 – Chet

+0

你確定你的大容量拷貝參與了交易嗎?myCon從哪裏來?另外[有一個構造函數](https://msdn.microsoft.com/en-us/library/wftd1yfz(v = vs.110).aspx),它接受SqlBulkCopy的事務,不使用它會影響行爲?編輯:另外,因爲它看起來像你使用的實體框架,有擴展[讓你批量插入EF](https://efbulkinsert.codeplex.com/),它可能會比SqlBulkCopy稍慢,但它可以讓你爲單行和批量行保留單個模型。 –

回答

2

IsolationLevel僅指讀取而不寫入。如果你的一個客戶正在寫數據,另一個客戶應該能夠讀取交易開始前的數據,但是,它不能同時寫入。

+0

但是,這似乎是SqlBulkCopy類的特定情況,當我使用Inserts語句而不是大容量副本進行Snapshot隔離時,會出現類似的情況它將允許其他人在包裝事務未完成之前插入到同一個表中 – user2945722

+1

您可以設置你的'BatchSize' = 1000',它應該減少回滾時間 – Jaco

1

爲減少阻塞時間,您可以做的一件事情是批量複製到(唯一)暫存表中,而不是直接複製到目標表中。這根本不必在交易中。一旦所有數據都在暫存表中,請將其複製到事務中的目標表中。這不會完全阻止塊的可能性。但是,從數據庫中複製數據通常會很快,特別是在數據可能被緩存的情況下。唯一可能的棘手問題是創建uique staging表(如果它們不是唯一的,只需將問題從一個表移動到另一個表)。