并行处理多个sql语句导致死锁

时间:2016-06-30 16:26:43

标签: c# sql-server

我正在处理一个项目,该项目涉及处理大量文本文件,并导致将记录插入mssql数据库或更新现有信息。

编写sql语句并将其存储在列表中,直到文件处理完毕。 然后处理该列表。每个语句一次只处理一个,但因为这可能是成千上万的语句,并且可能会创建一个非常长的运行过程。

为了尝试加快这个过程,我引入了一些并行处理,但这偶尔会导致以下错误:

  

事务(进程ID 94)在锁定时死锁通讯   用另一个进程缓冲资源并被选为   僵局受害者。重新运行该交易。

代码如下:

public static void ParallelNonScalarExecution(List<string> Statements, string conn)
    {
        ParallelOptions po = new ParallelOptions();
        po.MaxDegreeOfParallelism = 8;
        CancellationTokenSource cancelToken = new CancellationTokenSource();
        po.CancellationToken = cancelToken.Token;
        Parallel.ForEach(Statements, po, Statement =>
        {
            using (SqlConnection mySqlConnection = new SqlConnection(conn))
            {
                mySqlConnection.Open();
                using (SqlCommand mySqlCommand = new SqlCommand(Statement, mySqlConnection))
                {
                    mySqlCommand.CommandTimeout = Timeout;
                    mySqlCommand.ExecuteScalar();
                }            
            }
        });
    }

我相信更新声明在他们想要实现的目标方面很简单:

UPDATE TableA SET Notes = 'blahblahblah' WHERE Code = 1 
UPDATE TableA SET Notes = 'blahblahblah', Date = '2016-01-01' WHERE Code = 2
UPDATE TableA SET Notes = 'blahblahblah' WHERE Code = 3 
UPDATE TableA SET Notes = 'blahblahblah' WHERE Code = 4
UPDATE TableB SET Type = 1 WHERE Code = 100
UPDATE TableA SET Notes = 'blahblahblah', Date = '2016-01-01' WHERE Code = 5
UPDATE TableB SET Type = 1 WHERE Code = 101

解决此问题的最佳方法是什么?

2 个答案:

答案 0 :(得分:0)

线程A更新资源X并且不提交并且可以继续执行更多更新。 线程B更新资源y并且不提交并且可以继续进行更多更新。 此时,两者都有未提交的更新。

现在,线程A更新资源y并等待线程B的锁定。 线程B没有被任何东西阻挡,所以它继续,最终尝试更新资源x并被锁定A在x上阻塞。 现在他们陷入僵局。这是一个僵局,没有人可以继续提交,所以系统杀了一个。 您必须更频繁地提交以减少死锁的可能性(但这并不能完全消除这种可能性),或者您必须仔细订购更新,以便在继续对y进行任何更新之前完成并完成对x的所有更新

答案 1 :(得分:0)

从我看到你不想做你正在做的事情。我不建议使用多个更新语句来影响不同线程上的相同数据/表。这是种族条件/死锁的滋生。在你的情况下,它应该是安全的,但如果在任何时候你改变了where条件并且存在重叠,你就会遇到竞争条件问题。

如果你真的想用多线程来加速这一点,那么在一个线程上拥有tableA的所有更新语句,在一个线程上拥有tableB上的所有update语句。另一个想法是阻止你的更新声明。

UPDATE TableA SET Notes = 'blahblahblah' WHERE Code IN (1,2,3,4,5)
UPDATE TableA SET Date = '2016-01-01' WHERE Code IN (2,5)
UPDATE TableB SET Type = 1 WHERE Code IN (100,101)

以上这些陈述应该能够在一个简洁的环境中独立执行,因为没有两个陈述会影响同一列吗?