实时跟踪SQL查询的更改

时间:2010-10-31 21:06:25

标签: sql performance sql-server-2005 nhibernate

以下是我的情况:

  1. 用户A必须监控sql查询的结果问。
  2. 用户B可以修改可能会改变Q
  3. 结果的数据
  4. 在整个数据库上运行Q很慢
  5. 我想要的是:每当用户B修改数据时: 使用创建,更新或删除,然后生成Q的结果的增量。 即返回(已修改的列表,已创建的列表,已删除的列表)三元组。

    因此,更新Q会更快。

    实现细节:SQL Server 2005,带有NHibernate层。目前,用户A 在轮询模式下每隔10秒运行Q.

    我的一个想法是创建数据库模式的内存副本,以及用户B 进行更改,然后在内存副本中进行此更改,然后运行Q. 在这个内存中的副本。

    有更好的方法吗?

    Post-Script:感谢所有详细的评论。我决定按如下方式实现此功能:

    1. 使用NHibernate PostUpdate事件在数据库发生更改时收到通知
    2. 在内存中的更新集合中运行LINQ to Object查询
    3. 对于在系统中注册的每个SQL查询,将结果列表存储在内存中的Redis服务器上(没有持久性到磁盘)
    4. 如果LINQ查询表明更新与给定查询相关,即更改结果集,则更新Redis上的列表
    5. 使用某种类型的通知(例如Redis Pub / Sub)来通知用户对给定查询的更改
    6. 在Redis上更新列表时,传入sql server更新时间戳。需要在Redis端的一些代码来解决基于时间戳的冲突。如果使用较低的时间戳传入更改,请忽略。

5 个答案:

答案 0 :(得分:3)

好的,如果没有使用某种类型的大量overhad / polling查询来访问服务器,就没有办法做到这一点。因为SQL不是像我这样的人所知道的“自动收报机”。它不是分发实时更新。 SQL几乎是“问问你得告诉”。因此,“让我获得实时更新”意味着“我们还在那里吗?我们在那里吗?我们还在吗?”所有的时间,就像史瑞克2中的驴子一样。不过,SQL Server是一个更好的回答,并且很乐意一直回答“尚未”,但它会导致负载 - 或导致延迟。

大多数人在做你做的事情在数据库之外做。基本上通过处理更新的应用程序服务器运行,同时将它们写入数据库,分发更新信息。有些人表现得非常好 - 我从一个数据库中获得了一个数据,每秒处理大约250,000次更新。安静时间 - 峰值每秒约600,000次更新。所有这些都是对已知行数(约150万)的更新。 udpates在全球范围内分布并且不会导致数据库负载 - 因为分发是在应用程序层中的数据库外部完成的。实时。哦,这里的“最小延迟”是“尽可能快”。

没有办法像SQL Server一样分配结果,就像你想要FAST和EFFICIENT一样。您总是会遇到以某种方式妨碍您的查询语义。

所提供的答案仍然是正确的 - 但只有在小批量场景或可能出现明显延迟(0.5秒向上)的情况下才可行(对不起,在我的世界中,实时处理SLOW系统的处理时间不到5毫秒)。

您所寻找的是许多人拥有的标准问题......财务数据。实时交易系统需要信息FAST和REAL TIME并且拉动数据库是不可行的。如果您想要一个可扩展的解决方案(或需要一个),请在该区域查找方法。

答案 1 :(得分:2)

在SQL Server 2005中,他们引入了Service Broker。您可以将其用作队列。您从触发器发送消息(通过向表中添加记录),另一个进程调用存储过程,该存储过程设置为等待队列中的消息(表中的记录)。在添加此消息之前,存储过程将在那里等待(我认为存在超时设置 - 但我认为还有一个无限选项)。

In this blog post,海报展示了一个使用触发器中的Service Broker来提高性能的示例。

答案 2 :(得分:0)

一种方法是优化轮询查询。确保表格中有一列用于跟踪上次更新的时间。然后创建一个以UpdateDt开头的索引。然后,轮询查询可以执行:

select  *
from    TheBigTable
where   UpdateDt > 'LastTimeIChecked'

这将非常快,因为UpdateDt上有一个索引。它仍然是一个相当简单的代码/设置。

P.S。如果对哪个用户进行了更改很重要,您还可以将UpdatedBy添加到表和索引中。

答案 3 :(得分:0)

用户B多久更新一次数据?最好不要让A轮询更改,但让B导致一些事件发信号通知A数据有变化。 À可以简单地等待这个事件。 该事件可以保存您想要的任何数据。也许B对数据做出了很大的改变。 这样可以节省轮询导致的负载,以及A经历的延迟最小化。

答案 4 :(得分:0)

您可以在sql数据库旁边使用类似最近更改列表的内容。更改列表与rss feed类似。当rss-reader下载博客的feedurl时,feed会在第一次加载所有文章,之后只加载新文章。所描述的应用程序的rss-feed与原始的rss-feed略有不同,因为它不仅包含新文章,还包含文章和删除文章的更改。为了优化性能,可以间隔(秒或毫秒)读取rss-feed,并以一定间隔写入(批量更改或时间间隔后更新文件)。在UI中一次显示大量数据时,可能需要使用sql查询进行第一次显示,然后轮询rss-feed以获得可接受的性能。可以使用sql-query和rss-feed读取和更新UI的最大更改次数限制Feed中的更改次数。 rss-feed可以使用消息队列或esb实现,但您也可以使用不同的方式。 feed中的数据可以是xml,json,二进制序列化对象,也可以是UI中最容易使用的对象。 feed可以存储在某种缓存中,直接存储Ram内存或静态文件。您可能必须向数据库添加版本号列,并在每次更改时增加该编号,以便可以决定在第一次加载时从数据库中读取的内容以及需要从rss-feed处理哪些更改。 / p>

读:

  1. 使用Sql-query加载初始数据
  2. 等待时间间隔过去
  3. 使用更改阅读rss-feed
  4. 使用新更改更新用户界面
  5. 转到2
  6. 书写

    1. 开始交易
    2. 将更改写入sql database
    3. 将更改写入rss-feed
    4. 提交交易
    5. 将第3步写入消息队列并处理写异步可能是可以接受的。

      显示“实时”变化的一个主要问题是,实时并不意味着零秒,而是“用户可以解释变化的时间”,这对于多玩家第一人来说是0.05秒之间的事情射击游戏,30分钟或更长时间,由经理要求的报告,由秘书打印出来,并在经过几次电话后由经理阅读。