导致死锁的SQLBulkCopy

问题描述:

我有下面的代码..它实际上使用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的选择只会执行一个共享锁,但是插入(就像你一样做)将采取独占锁。 –

大容量插入将需要插入行到表中。插入行需要专用锁。获得的确切锁定取决于并发模型。

如果您指定TableLock选项,您的进程将尝试获取独占表锁。如果您的进程首次获取共享表锁,这肯定会导致死锁,其他进程具有共享的行锁,并且这两个进程都尝试将其锁升级为独占锁。

有几种方法,以获取有关死锁的更多信息: