C# SQLBulkCopy导致死锁

C# SQLBulkCopy导致死锁,c#,sql-server,deadlock,sqlbulkcopy,C#,Sql Server,Deadlock,Sqlbulkcopy,我有以下代码..它实际上使用SQLBulkCopy将数据插入目标。由于死锁,此代码在源SQL server中经常失败。仅供参考,在我们执行大容量复制时,正在复制的表可以使用(我的意思是一些插入/选择将运行) 这是问题的起因还是“小报”的暗示与此有关?据我所知,TABLOCK只获取共享锁,这应该不是问题 using (var reader = srcConnection.ExecuteReader($"select * from [{DatabaseName}].[{schemaName}].[{

我有以下代码..它实际上使用SQLBulkCopy将数据插入目标。由于死锁,此代码在源SQL server中经常失败。仅供参考,在我们执行大容量复制时,正在复制的表可以使用(我的意思是一些插入/选择将运行)

这是问题的起因还是“小报”的暗示与此有关?据我所知,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);
    }
}
使用(var reader=srcConnection.ExecuteReader($“从[{DatabaseName}].[{schemaName}].[{tableName}]]中选择*)
{
const SqlBulkCopyOptions bulkCopyOptions=SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.FireTriggers|
SqlBulkCopyOptions.KeepNulls |//不要用目标中的默认值替换空值
SqlBulkCopyOptions.KeepIdentity;
//使用源中的标识值,不要在目标中生成标识。
使用(var bcp=new-SqlBulkCopy(dstConnection.ConnectionString,bulkCopyOptions))
{
常数int三分钟=60*3;
bcp.BulkCopyTimeout=threeMinutes;//超时用于单个批次
bcp.BatchSize=5000;
bcp.DestinationTableName=$“[{DestinationDatabaseName}].[{schemaName}].[{tableName}]”;
bcp.EnableStreaming=true;
foreach(table.Columns.Cast()中的var col,其中(c=>!c.Computed))
{
bcp.ColumnMappings.Add(col.Name,col.Name);
}
bcp.WriteToServer(读卡器);
}
}

大容量插入需要在表中插入行。插入行需要独占锁。获得的确切锁将取决于并发模型

如果指定
表锁
选项,则进程将尝试获取独占表锁。如果您的进程首先获取共享表锁,而另一个进程具有共享行锁,并且两个进程都试图将其锁升级为独占锁,那么这肯定会导致死锁

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

  • 使能
  • 经营
  • 监视器

我认为你是对的。阅读本文,我们不会同时填充目的地,并且我们的目的地表是堆(即,没有索引)。更多关于死锁的起源似乎是源表,而不是目标表。我认为您对TABLOCK的理解是错误的,“TABLOCK-指定获取的锁应用于表级别。获取的锁的类型取决于正在执行的语句。”(我的重点),因此带有TABLOCK的select只能执行共享锁,但是插入(就像您正在做的)将使用独占锁。