CLR触发器状态

本文关键字:状态 触发器 CLR | 更新日期: 2023-09-27 17:59:17

我考虑使用CLR触发器而不是传统的T-SQL触发器,因为我需要使用一些已经在C#中实现的逻辑。我知道SQL server支持CLR集成,在我的情况下,它似乎是一个值得尝试的解决方案。

但是,我想要执行的操作可能有些缓慢。速度不够慢,无法完全排除在触发操作中使用它们的可能性,但在插入数十万条记录时,速度可能明显较慢。最慢的部分可以从缓存中受益匪浅,我想这将是非常少的缓存未命中和数千次缓存命中。在这一点上,这一切都引出了一个问题:CLR触发器可以有任何状态吗?更重要的是,这种状态的生命周期是什么?

我想我可以使用触发器类的静态字段来保存一些状态,但我不知道它何时初始化(服务器何时启动?事务启动时?未指定?)。我不确定这是否是安全的途径,因此询问在CLR触发器中使用某些状态的常见做法是什么(如果有的话)。

为了避免混淆:我需要缓存CLR对象,而不是某些SQL查询的结果,所以这与SQL Server本身的缓存能力无关,我想缓存一些不属于数据库的数据。另外,我考虑CLR并不是因为我不能在t-SQL中进行字符串操作和绑定检查。我需要执行一些在CLR类库中实现的逻辑,这些逻辑有很多依赖关系。在这种情况下,我是否应该使用触发器是另一个几乎与此无关的问题。

非常感谢。

PS:我将感谢任何关于该主题的评论和见解,即使是那些没有直接回答我问题的评论和看法,但请不要把一切都说成是"触发器是邪恶的,永远不应该使用"answers"CLR集成很慢,是一个主要的兼容性问题"。此外,我知道它可能会对某些人发出"过早优化"的尖叫,但目前我只想知道我的优化选项是什么,因为我是SQL server中CLR集成的新手。我不会优化它,除非分析结果表明是这样,但我不想实现整个过程,因为我意识到它太慢了,我对此无能为力

我使用SQL Server 2008和.NET 3.5。

CLR触发器状态

虽然可以在SQLCLR Trigger类中使用static类字段来缓存值,但有几件事需要非常小心:

  1. 您计划缓存多少数据?您不想占用太多的内存,而SQL Server应该使用这些内存进行查询。

  2. 每个数据库、每个程序集所有者(即程序集上的AUTHORIZATION)都有一个AppDomain。这意味着任何特定程序集中的代码都在所有SQL Server会话(即SPID)之间共享。如果数据只是查找数据,不会根据与静态字段交互的进程而改变,那么这是可以的。但是,如果每个进程的数据不同,那么这将产生"奇怪"的行为,除非您将当前TransactionID等值与进程相关联。

  3. 如果数据是按进程的,假设你找到了区分每个特定SPID/SESSION的方法,你将如何清理旧数据?它将存在于内存中,直到显式删除或卸载AppDomain为止。对于旨在与每个人共享的通用查找数据来说,这不是问题,因为这种类型的数据不会随着每个新进程的增加而增加。但除非清除,否则每个进程的数据将不断增加。

  4. AppDomains可以在任何时候卸载,原因多种多样(内存压力、程序集的丢弃/重新创建、与程序集相关的安全更改、与数据库相关的安全性更改、运行DBCC FREESYSTEMCACHE('ALL')等)。如果缓存的数据会在连续进程之间造成不同的结果,如果一个进程依赖于前一个进程缓存的数据,那么这就不能保证有效。如果在进程之间丢弃缓存只会导致需要重新加载缓存,那么应该没问题。

其他注意事项(但无需谨慎):

  1. 当在程序集中调用第一个方法时,将加载程序集域,其中程序集所在的数据库和作为该程序集授权人的用户当前没有正在运行的AppDomain。

  2. 由于上述原因之一,AppDomain将一直处于加载状态,直到SQL Server卸载它们,但这些情况都不一定会发生。也就是说,AppDomain可以在很长一段时间内保持加载状态(即,直到服务器/服务重新启动)。

  3. 每次引用程序集内部的方法时,都会加载每个程序集。

  4. 为了利用加载事件,可以将代码放置在静态类构造中。请注意,没有可用的SqlContext,因此不能在使用进程内上下文连接(即Context Connection = true)的静态类构造函数中生成任何SqlConnections。