2016-08-24 325 views
2

我有下面的代碼..它實際上使用SQLBulkCopy插入數據到目的地。由於死鎖,此代碼在源SQL服務器中經常失敗。僅供參考,在我們執行批量複製時,正在複製的表格可能正在使用中(我的意思是某些插入/選擇將在運行)。導致死鎖的SQLBulkCopy

這是造成問題或「TABLOCK」提示有什麼關係嗎?根據我的理解,TABLOCK只獲取共享鎖,不應該成爲問題。

using (var reader = srcConnection.ExecuteReader($"select * from [{DatabaseName}].[{schemaName}].[{tableName}]")) 
{ 
    const SqlBulkCopyOptions bulkCopyOptions = SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.FireTriggers | 
               SqlBulkCopyOptions.KeepNulls | //Do not replace nulls with defaults in destination 
               SqlBulkCopyOptions.KeepIdentity; 
     //Use the identity values from source, do not generate identities in destination. 

    using (var bcp = new SqlBulkCopy(dstConnection.ConnectionString, bulkCopyOptions)) 
    { 
     const int threeMinutes = 60*3; 

     bcp.BulkCopyTimeout = threeMinutes; //Timeout is for a single batch 
     bcp.BatchSize = 5000; 
     bcp.DestinationTableName = $"[{DestinationDatabaseName}].[{schemaName}].[{tableName}]"; 
     bcp.EnableStreaming = true; 

     foreach (var col in table.Columns.Cast<Column>().Where(c => !c.Computed)) 
     { 
      bcp.ColumnMappings.Add(col.Name, col.Name); 
     } 

     bcp.WriteToServer(reader); 
    } 
} 
+0

我認爲你是對的。閱讀此[鏈接](https://social.msdn.microsoft.com/Forums/sqlserver/en-US/932cd26c-53fc-49c0-b082-e7f5f05a9801/deadlock-when-using-sqlbulkcopy-to-concurrently-insert- row-into-a-single-nonempty-table?forum = sqldatabaseengine) – Keppy

+0

我們不是同時填充目標,我們的目標表是堆(即沒有索引)。更多的來自死鎖的起源似乎是源表,但不是目的地。 – SumanKumar

+0

我認爲你對TABLOCK的理解是錯誤的,[來自MSDN上的文檔](https://msdn.microsoft.com/en-us/library/ms187373.aspx)「* TABLOCK - 指定應用獲取的鎖**所獲取的鎖的類型取決於正在執行的語句**。*「(強調我的),所以帶有TABLOCK的選擇只會執行一個共享鎖,但是插入(就像你一樣做)將採取獨佔鎖。 –

回答

2

大容量插入將需要插入行到表中。插入行需要專用鎖。獲得的確切鎖定取決於併發模型。

如果您指定TableLock選項,您的進程將嘗試獲取獨佔表鎖。如果您的進程首次獲取共享表鎖,這肯定會導致死鎖,其他進程具有共享的行鎖,並且這兩個進程都嘗試將其鎖升級爲獨佔鎖。

有幾種方法,以獲取有關死鎖的更多信息: