我使用一个表作为消息队列,并通过使用SqlDependency"注册"更新。无论我读到哪里,人们都在说"注意它的局限性",但没有具体说明它们是什么。从我收集到的信息来看,当表的更新频率很高时,您会遇到问题;幸运的是,我每分钟最多只能看到10 - 20个值。
对SqlServer的其他限制/影响是什么?
我能找到的最完整的列表如下:
- SELECT语句中的预计列必须显式声明,并且表名必须由两部分名称限定。注意,这意味着语句中引用的所有表必须在同一个数据库中。
- 语句不能使用星号(*)或table_name。*指定列的语法
- 语句不能使用未命名的列或重复的列名。
- 语句必须引用基表。
- 语句不能引用包含计算列的表。
- SELECT语句中的投影列不能包含聚合表达式,除非该语句使用了GROUP BY表达式。当提供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。
- 语句不能引用同义词
- 语句不能有基于double/real数据类型的比较或表达式。
- 语句不能使用TOP表达式
额外的参考:
- 使用查询通知
除此之外,对于那些考虑使用SqlDependency来接收更改通知的人,我一直在生产中使用这种方法,并且我发现它存在问题。我正在调查它,看看问题是否与我的代码有关,但主要问题是:
-
如果您快速连续触发多个更改,您并不总是得到相同数量的事件通过代码。在我的代码中,如果两个新记录一个接一个地插入,我只得到一个通知(对于最后一个)。
-
没有办法知道添加的记录。因此,如果您添加了一个新记录,并且代码触发以接收通知,则代码中没有办法知道该新记录的id,因此您需要查询数据库。
花了一天时间追查SQL Service Broker不工作的问题,根本原因是在存储过程中引用数据库。
例如,这个select
在SQL Management Studio中运行良好:
select [MyColumn] from [MyDatabase].[MySchema].[MyTable]
然而,这被SQL Service Broker拒绝,因为我们在select语句中引用了数据库,并且SqlDependency
的回调与SqlNotificationEventArgs e
中的Invalid
一起返回,参见http://msdn.microsoft.com/en-us/library/ms189308.aspx。
将传递给SqlDependency的SQL修改为以下语句可以消除错误:
select [MyColumn] from [MySchema].[MyTable]
<标题> 更新上面的例子只是SQL Service Broker所依赖的SQL语句的众多限制之一。有关限制的完整列表,请参见SqlDependency的限制是什么。
的原因吗?SQL Service Broker使用的SQL语句在幕后被转换成指令,以监视SQL Transaction Log中对数据库的更改。这种监视是在SQL Server的核心执行的,这使得它在检测表的更改时非常快。然而,提高速度是有代价的:不能使用任何SQL语句,必须使用可以转换为指令的SQL语句来监视SQL事务日志。
标题>请注意,您不能在存储过程中使用nolock提示,否则依赖项将始终无效,因此您对其进行的任何缓存都将永久地重新查询数据库。
with (NOLOCK)
文档中似乎没有提到这一点(据我所知)。
在执行过程脚本
之前需要以下SET选项SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
其他人认为这些SET选项也是必需的,但我不这么认为。无论如何,这样设置它们是一个好主意。
SET CONCAT_NULL_YIELDS_NULL ON
SET QUOTED_IDENTIFIER ON
SET NUMERIC_ROUNDABORT OFF
SET ARITHABORT ON
我在使用这项技术时遇到的另一个大问题是:订阅者连接需要具有Create Procedure权限。我在工作中的应用程序的web服务层目前作为受限制的用户运行。要使用SQLDependency设置通知,我必须打开该用户以创建进程。听起来在被拥有的道路上迈出了很好的一步。
要克服这些限制,您可以尝试使用SqlTableDependency。看看www.sqltabledependency.it
它使用Service Broker。因此,它不能在非托管SQL Azure实例上工作。因此,如果你正在使用SQL Azure,或者可能会使用,请谨慎。
https://learn.microsoft.com/en-us/azure/sql-database/sql-database-features服务代理
单数据库和弹性池支持:
没有受管实例支持:
可以,但只能在实例内。参见Service Broker差异
所以可能不是很适合,除非你的所有环境都可以使用它!