具有数据库读取功能的多线程应用程序-每个线程唯一的记录

时间:2018-12-19 08:12:22

标签: c# .net sql-server multithreading design-patterns

我有一个.net应用程序,它基本上每次(每5分钟)从数据库表中读取大约一百万条记录,进行一些处理并更新将该记录标记为已处理的表。

当前,应用程序在单线程中运行,从数据库表中获取大约4K条记录,进行处理,更新记录,然后获取下一条。

我正在使用带有存储过程的dapper。我正在使用4K记录进行检索,以避免DB表锁定。

在多个线程中检索记录并同时确保每个线程都获得新的4K记录的最佳方法是什么?

我目前的想法是,我将首先检索1M记录的ID。按升序对ID进行排序,并将其分成4K批次,记住批次中的最低和最高ID。 然后,在每个线程中,我将调用另一个存储过程,该存储过程将通过指定所检索记录的最低和最高ID来检索完整记录,并对其进行处理等等。

我不知道有没有更好的模式?

1 个答案:

答案 0 :(得分:2)

我发现这个问题很有趣,部分原因是我在原则上尝试做类似的事情,还因为我没有看到针对它的超直观的行业标准解决方案。然而。

如果您正确编写SQL查询,那么您打算做的事情将起作用。 使用ROW_NUMBER / BETWEEN应该可以实现。 我将在此处编写和记录其他一些替代方案以及收益/警告。

并行处理

我知道您想在SQL Server中执行此操作,但是作为参考,Oracle将其作为关键字实现,您可以并行查询内容。

文档:https://docs.oracle.com/cd/E11882_01/server.112/e25523/parallel002.htm

SQL的实现方式有所不同,您必须通过更复杂的关键字将其显式打开,并且必须使用特定版本:

一篇不错的文章在这里:https://www.mssqltips.com/sqlservertip/4939/how-to-force-a-parallel-execution-plan-in-sql-server-2016/

您可以将并行处理与SQL CLR集成相结合,这将有效地执行您在SQL中要做的事情,而SQL则管理数据块而不是您在线程中。

SQL CLR集成

您可能会想到的一个不错的功能是在SQL Server中执行 .net代码。这里的文档:https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/introduction-to-sql-server-clr-integration

这基本上将允许您在SQL Server中运行C#代码-节省读/处理/写往返的时间。他们还改进了与此相关的持续集成-这里的文档:https://docs.microsoft.com/en-us/sql/integration-services/sql-server-integration-services?view=sql-server-2017

不幸的是,查看QoS /获取日志以防万一出了问题,实际上并不像在工人手中处理它那样容易。

使用单个线程(如果您正在从外部源中读取内容)

只有在满足某些条件的情况下,并行才对您有好处。以下是Oracle文档的内容,但也适用于MSSQL:https://docs.oracle.com/cd/B19306_01/server.102/b14223/usingpe.htm#DWHSG024

  

并行执行可改善以下方面的处理:

     
      
  • 需要大表扫描,联接或分区索引扫描的查询
  •   
  • 创建大索引
  •   
  • 创建大表(包括物化视图)
  •   
  • 批量插入,更新,合并和删除
  •   

还有设置/环境要求

  

并行执行有利于以下所有系统   特点:

     
      
  • 对称多处理器(SMP),集群或大规模并行   系统
  •   
  • 足够的I / O带宽
  •   
  • 未充分利用或间歇使用的CPU(例如,其中   CPU使用率通常低于30%)
  •   
  • 足够的内存来支持其他内存密集型进程,   例如排序,哈希和I / O缓冲区
  •   

还有其他限制。当您使用多个线程来执行您建议的操作时,如果其中一个线程被杀死/无法执行某项操作/引发异常等……您将绝对需要处理该问题-一直保持到发生什么情况为止最后一个已处理的索引-因此您可以重试其余记录。 使用单个线程,变得更简单。

结论

假设数据库建模正确且无法进一步优化我想说的是最简单的解决方案,单线程是最好的解决方案。更容易记录和跟踪错误,更容易实现重试逻辑,我想说的是这些远远超过了从并行处理中看到的好处。您可能会在并行处理位中寻找批量更新的信息,可以对数据库进行操作,但是除非您在SQL中拥有CLR DLL(您将以并行方式调用它的方法),否则我看不出有什么克服的好处。您的系统在运行并行查询时也必须采取某种特定的方式,以提高效率。

您当然可以将您的工作角色设计为异步的,而不是阻塞每个记录的处理。因此,您仍将是多线程的,但查询将在单个线程中进行。

修改为结论

在今天与我的同事讨论之后,值得补充的是,即使使用单线程方法,您也必须能够从故障中恢复,因此,对于< em>恢复/正常失败的要求并记住您处理的内容不变。不过,鉴于必须编写更复杂的代码来跟踪多个线程及其状态,因此如何恢复。