轮询MSSQL表的替代方法

use*_*205 5 c# sql sql-server polling

我有一个MSSQL表,其中包含我的Windows服务应根据时间戳处理的计划任务,我想知道我有什么选择来轮询这样的表

SELECT *
FROM mydb
WHERE SYSUTCDATE() >= timestamp
Run Code Online (Sandbox Code Playgroud)

我可能需要至少每5秒轮询一次表格.基本上我希望我的Windows服务在表中的时间戳设置的时间处理数据.

对我来说,这似乎不是最有效的方式.我已经研究过DML和CLR触发器,我认为它们不会起作用,因为它们会在数据发生变化时触发,而不是在时间戳已经过去时触发.思考?


更新2:

我已经意识到把它称为"预定任务"是一个糟糕的措辞选择,所以我将尝试更详细地描述它.

该项目的目标是根据我们的业务逻辑向人们发送电话通知.一种情况是应该根据内部事件在特定时间打电话给多个人.可以多次呼叫同一个人,具体取决于电话呼叫的应答方式.因此,为了简化操作并消除管理每个电话呼叫状态的复杂性和开销,我认为通过将每个电话呼叫作为表中的条目来预先安排每个电话呼叫是个好主意.应停止通知时,将从表中删除待处理的电话呼叫.这将使Windows服务的设计变得非常简单.它所做的就是根据表中的时间戳发送通知.


更新1:

消息队列

我还没弄明白发件人如何在适当的时候将消息放入队列.

的SqlDependency

我使用来自使用SqlDependency检测更改的示例代码时遇到问题.由于某种原因,OnChange事件最初只会被触发,以后什么都不会发生.

更新:我不认为SqlDependency会工作,因为表中的数据不会更改以使触发器触发.

void Initialization()
{
   // Create a dependency connection.
   SqlDependency.Start(connectionString, queueName);
}

void SomeMethod()
{
   // Assume connection is an open SqlConnection.

   // Create a new SqlCommand object.
   using (SqlCommand command=new SqlCommand(
      "SELECT timestamp,othercolumn FROM mydb WHERE SYSUTCDATE() >= timestamp", 
       connection))
   {

   // Create a dependency and associate it with the SqlCommand.
   SqlDependency dependency=new SqlDependency(command);
   // Maintain the refence in a class member.

   // Subscribe to the SqlDependency event.
   dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);

   // Execute the command.
   using (SqlDataReader reader = command.ExecuteReader())
   {
      // Process the DataReader.
   }
}
Run Code Online (Sandbox Code Playgroud)

Jer*_*ert 4

好吧,首先,考虑根本不这样做。将所有有用的工作推到数据库中配置的定期任务是一种脆弱的设计,当有人配置错误时很容易破坏(很容易做到,因为您需要相当高级的触发器来检查计划一致性),而且它也往往当任务实际上具有隐藏的依赖关系时,创建一个难以理解的系统(如果 A 在 B 之前没有运行一段时间,就会出现问题,诸如此类的事情)。资料来源:在三个不同的公司和三种不同的平台/技术中使用三个这样的系统的个人经验,不知何故它们都遇到了相同的问题,所以显然这是一个问题。考虑使用配置文件将您想要安排的事情写成普通的旧代码。当然,它不会那么通用,但是必须维护它的人会感谢您,特别是当他们的需求变得更加复杂时。

SqlDependency即使您确实有受支持的查询,它也相当变化无常并且不容易使用。在您的情况下,正如您所注意到的,它不起作用,因为除非数据实际发生变化,否则数据库引擎不会发布通知 - 查询结果随着时间的推移而变化并不重要。正如 Nick 指出的那样,每 5 秒轮询一次数据库通常就可以了。如果您已经创建了索引mydb.timestamp(并且创建索引非常重要,因为每 5 秒执行一次表扫描是不行的),那么这会产生可以忽略不计的负载。

唯一的反对意见是延迟:如果对计划的任何更新必须早于每 5 秒一次,那么轮询就不够好。在这种情况下,您可以使用 Service Broker 并在发生变化时(可能来自触发器)立即向队列发布通知。事实上,SqlDependency在幕后使用相同的方法,因此您可以创建一个依赖项,以便在表中发生任何SELECT * FROM table更改时获取通知,然后执行实际查询以获得您需要的内容(可能会发现什么都没有)。但请注意:与定期重新加载相比,正确获取此代码而不被多次快速更新或连接中断所困扰并不是微不足道的,而且可能不值得。