数据库表插入来自多线程应用程序的锁

时间:2012-06-07 19:38:16

标签: c# .net sql-server multithreading sql-server-2008

我有一个运行多线程的进程。

进程具有要处理的项的线程安全集合。

每个线程在循环中处理集合中的项目。

列表中的每个项目都由线程发送到存储过程,以将数据插入到事务中的3个表中(在sql中)。如果一个插入失败,则所有三个都失败。请注意,交易范围是每个项目。

插入非常简单,只需将一行(相关的外键)插入每个表中,并使用标识种子。没有读取,只需插入然后转到下一个项目。

如果我有多个线程试图处理他们自己的项目,每个项目都试图插入到同一组表中,这会因为事务锁定而产生死锁,超时或任何其他问题吗?

我知道每个线程必须使用一个数据库连接,我主要关注每个事务中表的锁级别。当一个线程将行插入3个表时,其他线程是否必须等待?除了自动标识需要递增之外,每个表没有行的依赖性。如果它是一个表级锁定来增加标识,那么我想其他线程将不得不等待。插入物有时可能很快或者可能不快。如果它必须等待,那么进行多线程是否有意义?

多线程的目标是加速项目的处理。

请分享您的经验。

PS:身份种子不是GUID。

4 个答案:

答案 0 :(得分:5)

在SQL Server中,多个插入到单个表中通常不会自行阻塞。 IDENTITY生成机制是高度并发的,因此它不会序列化访问。插入可能相互阻塞,如果他们在唯一索引中插入相同的密钥(如果两者都尝试提交,其中一个也会遇到重复的密钥冲突)。你也有一个概率游戏,因为密钥被散列,但它只在大型交易中发挥作用,见%%LOCKRES%% COLLISION PROBABILITY MAGIC MARKER: 16,777,215。如果事务插入到多个表中也不应该有冲突,只要再次插入的键是不相交的(如果插入是master-child-child,这自然会发生。)

话虽这么说,二级索引的存在,特别是外键约束可能引入阻塞和可能的死锁。没有确切的模式定义是不可能告诉你是否或不容易死锁。任何其他工作负载(报告,读取,维护)也会增加争用问题,并可能导致阻塞和死锁。

真的非常高端的部署(不需要在论坛上寻求建议......)可能会受到插入热点症状的影响,请参阅Resolving PAGELATCH Contention on Highly Concurrent INSERT Workloads

BTW,从多个线程执行INSERT很少是增加负载吞吐量的正确答案。有关如何解决 问题的好建议,请参阅The Data Loading Performance Guide。最后一条建议:多线程也很少能够让任何程序更快。异步编程几乎总是正确的答案。请参阅AsynchronousProcessingBeginExecuteNonQuery

作为旁注:

  

只需在每个表中插入一行(相关的外键),...   没有读,

这种说法实际上是矛盾的。外键意味着读取,因为它们必须在写入期间进行验证。

答案 1 :(得分:3)

如果存在身份,是什么让您认为它必须是表级锁定。我没有在任何文档中看到这一点,我只是在带有标识列的表上测试了带有(rowlock)的插入,并且它可以工作。

要最小化锁定,请使用行锁。对于所有存储过程,以相同的顺序更新表。

你有三个表插入每个最多10秒?我在事务中有一些插入命中多个表(其中一些表很大)并获得100 /秒。

查看您的桌面设计和按键。如果您可以选择一个表示插入顺序的聚类PK,并且如果您在插入之前可以进行排序,则会产生巨大的差异。检查是否需要任何其他索引。如果必须有其他索引,则监视碎片和碎片整理。

相关但不一样。我有一个数据加载器,必须解析一些数据,然后每晚加载数百万行但不在事务中。它在4个并行过程中优化,从空表开始,但问题是在两小时的加载吞吐量由于碎片而下降了10倍。我重新设计了表格,因此PK聚集索引处于插入顺序。丢弃任何其他没有产生至少50%选择凹凸的指数。在每晚插入第一次删除(禁用)索引并只使用两个线程。一个要解析的线程和一个要插入的线程。然后我在加载结束时重新创建索引。锤击指数的4个线程获得100:1的改进。是的,你有一个不同的问题,但审查你的表。我常常认为索引是为了小的选择好处而添加的,而不考虑插入和更新的命中。此外,当您构建索引并进行比较并且新索引没有碎片时,选择权益通常会被高估。

答案 2 :(得分:2)

像mssql这样的重型DBMS通常非常非常适合处理并发性。您同时执行的事务究竟会发生什么在很大程度上取决于您的TI级别(http://msdn.microsoft.com/en-us/library/ms175909%28v=sql.105%29.aspx),您可以根据需要设置它,但在这种情况下,我认为您不必担心死锁。

是否有意义 - 在不了解您的系统的情况下总是难以猜测。虽然不难尝试,所以你可以自己找到它。如果我猜的话,我会说如果您所有的线程都要以循环方式插入行,它将无助于您。

答案 3 :(得分:0)

其他线程无论如何都会等待,你的pc无法在每个给定时刻执行比你拥有的cpu核心更多的线程。
您写道,您希望使用多线程来加速处理。我不确定这是你可以自动给出/正确的东西。并行度级别及其对处理速度的影响取决于许多因素,这些因素非常依赖于处理,例如,是否涉及IO,或者每个线程是否应该仅用于内存处理。我认为,这是微软在其tpl框架中提供任务调度程序的原因之一,并且通常将此库中的可靠性视为应该在运行时设置的内容。
我认为你最安全的选择是运行测试查询/流程以确切了解会发生什么(当然,它仍然不会100%准确)。您还可以查看sql server的optimisitc concurrency功能,它允许无锁工作(我不知道它如何处理标识列)