12

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

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

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

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

插入非常简单,只需在每个表中插入一行(与外键相关),并带有标识种子。没有读取,只需插入然后继续下一项。

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

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

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

请分享你的经验。

PS:身份种子不是 GUID。

4

4 回答 4

7

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

话虽如此,二级索引和特别是外键约束的存在可能会引入阻塞和可能的死锁。如果没有准确的架构定义,就无法判断您是否容易出现死锁。任何其他工作负载(报告、读取、维护)也会增加争用问题,并可能导致阻塞和死锁。

非常非常高端的部署(不需要在论坛上寻求建议的那种......)可能会出现插入热点症状,请参阅解决高并发 INSERT 工作负载上的 PAGELATCH 争用

顺便说一句,从多个线程执行 INSERT 很少是增加负载吞吐量的正确答案。有关如何解决问题的好建议,请参阅数据加载性能指南。最后一个建议:多线程也很少是使任何程序更快的答案。异步编程几乎总是正确的答案。见和。AsynchronousProcessingBeginExecuteNonQuery

作为旁注:

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

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

于 2012-06-07T22:10:06.797 回答
4

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

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

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

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

相关但不一样。我有一个数据加载器,它必须解析一些数据,然后每晚加载数百万行但不在事务中。它从空表开始优化了 4 个并行进程,但问题是在加载两个小时后,由于碎片,吞吐量下降了 10 倍。我重新设计了表,因此 PK 聚集索引按插入顺序排列。删除了未产生至少 50% 选择凸起的任何其他索引。在每晚插入第一次删除(禁用)索引并仅使用两个线程。一个要解析的线程,一个要插入的线程。然后我在加载结束时重新创建索引。在 4 个线程锤击索引时得到了 100:1 的改进。是的,您有不同的问题,但请查看您的表格。我经常认为添加索引是为了小选择的好处,而不考虑插入和更新的命中。

于 2012-06-07T21:53:40.353 回答
2

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

无论它是否有意义 - 在不了解您的系统的情况下总是很难猜测。不过尝试起来并不难,所以你可以自己找出来。如果我猜的话,我会说如果你所有的线程都要做的是以循环方式插入行,那对你没有多大帮助。

于 2012-06-07T20:47:50.187 回答
0

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

于 2012-06-07T21:37:05.773 回答