【问题标题】:SQLBulkCopy causing deadlockSQLBulkCopy 导致死锁
【发布时间】:2016-08-24 13:11:43
【问题描述】:

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

这是导致问题还是“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);
    }
}

【问题讨论】:

  • 我认为你是对的。阅读此link
  • 我们没有同时填充目标,我们的目标表是堆的(即没有索引)。更多死锁的起源似乎是源表而不是目的地。
  • 我觉得你对TABLOCK的理解是错误的,from the documentation on the MSDN"TABLOCK - 指定获取的锁是应用在表级别的。获取的锁的类型取决于正在执行的语句”(强调我的),因此带有 TABLOCK 的选择只会执行共享锁,但插入(就像您正在执行的操作一样)会占用排他锁。

标签: c# sql-server deadlock sqlbulkcopy


【解决方案1】:

批量插入需要将行插入到表中。插入行需要排他锁。获取的确切锁取决于并发模型。

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

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

【讨论】:

    猜你喜欢
    • 2018-04-20
    • 2012-09-20
    • 2018-06-04
    • 2016-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    相关资源
    最近更新 更多