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

本文关键字:插入 数据库 多线程 应用程序 | 更新日期: 2023-09-27 18:36:40

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

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

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

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

插入

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

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

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

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

请分享您的经验。

PS:标识种子不是 GUID。

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

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

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

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

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

作为旁注:

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

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

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

为了尽量减少锁定,请使用行锁。 对于所有存储过程,请按相同的顺序更新表。

您是否在三个表中插入最多需要 10 秒? 我在交易中有一些插入,这些插入击中多个表(其中一些很大)并获得 100/秒。

查看表设计和键。 如果你能选择一个代表插入顺序的簇状PK,并且如果你能在插入之前进行排序,这将产生巨大的差异。 查看是否需要任何其他索引。 如果必须具有其他索引,请监视碎片并进行碎片整理。

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

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

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

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