SqlDependency有什么限制

flu*_*luf 42 c# sql-server-2005 sqldependency

我使用表作为消息队列,并使用SqlDependency"注册"以获取更新.我读到的每个地方的人都在说要注意它的局限性,但没有具体说明它们是什么.从我收集的内容来看,当表具有非常高的更新频率时,你会遇到问题,幸运的是我只看到每分钟最多10-20个值.

对SqlServer有哪些其他限制/影响?

Smu*_*202 61

我能找到的最完整的清单(从这里)如下:

  • 必须明确声明SELECT语句中的预计列,并且必须使用两部分名称限定表名.请注意,这意味着语句中引用的所有表必须位于同一数据库中.
  • 该语句可能不使用asterisk()或table_name.用于指定列的语法.
  • 该语句可能不使用未命名的列或重复的列名.
  • 该语句必须引用基表.
  • 该语句不得引用具有计算列的表.
  • 除非语句使用GROUP BY表达式,否则SELECT语句中的投影列可能不包含聚合表达式.提供GROUP BY表达式时,选择列表可能包含聚合函数COUNT_BIG()或SUM().但是,可能不会为可为空的列指定SUM().该语句可能未指定HAVING,CUBE或ROLLUP.
  • SELECT语句中用作简单表达式的投影列不得出现多次.
  • 声明不得包括PIVOT或UNPIVOT运营商.
  • 该声明不得包含UNION,INTERSECT或EXCEPT运算符.
  • 声明不得引用视图.
  • 该语句不得包含以下任何内容:DISTINCT,COMPUTE或COMPUTE BY或INTO.
  • 该语句不得引用服务器全局变量(@@ variable_name).
  • 该语句不得引用派生表,临时表或表变量.
  • 该语句不得引用其他数据库或服务器中的表或视图.
  • 该语句不得包含子查询,外连接或自连接.
  • 该语句不得引用大对象类型:text,ntext和image.
  • 声明不得使用CONTAINS或FREETEXT全文谓词.
  • 该语句不能使用行集函数,包括OPENROWSET和OPENQUERY.
  • 该语句不得使用以下任何聚合函数:AVG,COUNT(*),MAX,MIN,STDEV,STDEVP,VAR或VARP.
  • 该语句不得使用任何非确定性函数,包括排名和窗口函数.
  • 该语句不得包含用户定义的聚合.
  • 该语句不得引用系统表或视图,包括目录视图和动态管理视图.
  • 声明不得包含FOR BROWSE信息.
  • 该语句不得引用队列.
  • 该语句不得包含无法更改且无法返回结果的条件语句(例如,WHERE 1 = 0).
  • 该语句不能指定READPAST锁定提示.
  • 该声明不得引用任何Service Broker QUEUE.
  • 声明不得引用同义词.
  • 该语句不得基于双/实数据类型进行比较或表达.
  • 声明不得使用TOP表达式.

其他参考:

  • @Mou,这只是粗鲁 - 花点时间阅读答案:""声明不得使用TOP表达式."". (5认同)
  • 大多数这些规则/限制在一些重要的规则/限制中是显而易见的 我真的不知道每个人总是在谈论什么. (2认同)

Mat*_*rts 12

除此之外,对于其他任何考虑使用SqlDependency接收有关更改的通知的人,我一直在生产中使用这种方法,我发现它有问题.我正在调查它以查看问题是否与我的代码有关,但主要问题是:

  • 如果您快速连续触发多个更改,则不会始终获得通过代码的相同数量的事件.在我的代码中,如果一个接一个地插入2个新记录,我只收到一个通知(对于最后一个).

  • 无法知道添加的记录.因此,如果您添加新记录,并且代码触发以接收通知,则代码无法知道该新记录的ID,因此您需要查询数据库.

  • 我做了同样的观察.当时,我使用反射器和SQL Profiler的组合进行逆向工程SqlDependency.第一个问题是因为您收到的通知会折叠您设置的回调,而后者又会设置新的回调.第一个回调触发和第二个回调设置之间存在差距.如果您检查如何使用SQL事件探查器设置SQL对话框/对话/排队,您可以创建一个自定义实现,返回有关所需插入记录的详细信息,这将处理第二个问题.祝好运 (3认同)
  • 关于多个更改:每个SqlDependendy仅触发onChange一次.因此,如果在再次设置SqlDependency之前再次更改数据,那么onChange-class将比数据库更改少得多.IMO SqlDependency背后的想法是使用它来使缓存的数据无效,并在更改后再次读取整个集合. (2认同)
  • 对于第二点,如果要捕获新添加的记录,可以使用 SqlTabledependency 而不是 SqlDependency 。更多信息请参见:https://recordtablechanges.codeplex.com/ (2认同)

Con*_*ngo 9

花了一天时间追逐SQL Service Broker无法正常工作的问题,根本原因是在存储过程中引用了数据库.

例如,这select在SQL Management Studio中工作正常:

select [MyColumn] from [MyDatabase].[MySchema].[MyTable]
Run Code Online (Sandbox Code Playgroud)

但是,这是由SQL Service Broker的拒绝,因为我们是在SELECT语句引用数据库,并从回调SqlDependency回来与InvalidSqlNotificationEventArgs e,见http://msdn.microsoft.com/en-us/library/ms189308.aspx.

将传递给SqlDependency的SQL更改为以下语句消除了错误:

select [MyColumn] from [MySchema].[MyTable]
Run Code Online (Sandbox Code Playgroud)

更新

上面的示例只是SQL Service Broker依赖的SQL语句的许多限制之一.有关限制的完整列表,请参阅SqlDependency的限制.

原因?SQL Service Broker使用的SQL语句在后台转换为监视SQL事务日志以获取对数据库的更改的指令.此监视在SQL Server的核心中执行,这使得在检测对表的更改时非常快.但是,这种速度是有代价的:您不能只使用任何SQL语句,您必须使用一个可以转换为指令来监视SQL事务日志.


Dav*_*dge 5

请注意,您不能在存储过程中使用nolock提示,否则依赖项将始终无效,因此您在其上创建的任何缓存将永久地重新查询数据库.

with (NOLOCK) 
Run Code Online (Sandbox Code Playgroud)

这似乎没有在文档中提及(据我所知)

在过程脚本之前,需要以下SET选项

SET ANSI_NULLS ON
SET ANSI_PADDING ON  
SET ANSI_WARNINGS ON
Run Code Online (Sandbox Code Playgroud)

其他人则认为这些SET选项也是必需的,但我不认为它们是.不管怎么说,这样设置就好了.

SET CONCAT_NULL_YIELDS_NULL ON 
SET QUOTED_IDENTIFIER ON 
SET NUMERIC_ROUNDABORT OFF 
SET ARITHABORT ON
Run Code Online (Sandbox Code Playgroud)