【问题标题】:CLR Triggers stateCLR 触发器状态
【发布时间】:2011-06-14 09:47:07
【问题描述】:

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

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

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

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

非常感谢。

PS:我会感谢任何有关主题的 cmets 和见解,即使是那些不直接回答我的问题的人,但请不要全说“触发器是邪恶的,不应该”永远不会被使用”和“CLR 集成很慢并且是一个主要的兼容性问题”。另外,我知道它可能会向某人尖叫“过早的优化”,但目前我只想知道我的优化选项会发生什么,因为我是 SQL Server 中 CLR 集成的新手。除非分析结果表明,否则我不会对其进行优化,但我不想实现整个事情以意识到它太慢而且我无能为力。

我使用 SQL Server 2008 和 .NET 3.5。

【问题讨论】:

  • 缓存在内存中?这是 SQL Server 已经擅长的事情之一。
  • @Mitch Wheat:你能详细说明一下吗?
  • 对于正确指定和配置的 SQL Server 上的大多数数据库,80% 的“热”页面将由 RAM 提供,而不是文件系统(大型数据库除外)。如果不是这样,你还有其他问题......(不是我的反对票)
  • 您的触发器有表访问权限吗?如果是(这是一个触发器,当然你有),那么 CLR 不是 最好的选择。它慢:您选择了错误的解决方案。没有任何调整可以优化它:这就是我们使用纯 SQL 的原因。你的附言烦人:接受您选择的解决方案的局限性
  • @Mitch Wheat:我需要缓存 POCO,而不是关系数据

标签: c# sql-server triggers sqlclr


【解决方案1】:

虽然可以在 SQLCLR 触发器类中使用 static 类字段来缓存值,但您需要非常注意几件事:

  1. 您计划缓存多少数据?您不想占用 SQL Server 应该用于查询的太多内存。

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

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

  4. AppDomains 可以随时出于各种原因卸载(内存压力、程序集的删除/重新创建、与程序集相关的安全更改、与数据库相关的安全更改、运行DBCC FREESYSTEMCACHE('ALL') 等)。如果一个进程依赖于前一个进程缓存的数据,则缓存的数据可能会导致顺序进程之间的不同结果,则不能保证这可以正常工作。如果在进程之间删除缓存仅导致需要重新加载缓存,那么应该没问题。

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

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

    李>
  2. AppDomain 将保持加载状态,直到由于上述原因之一被 SQL Server 卸载,但这些情况都不一定会发生。这意味着,AppDomain 可以保持加载很长时间(即直到服务器/服务重新启动)。

  3. 每个程序集在第一次引用其中的方法时加载。

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

【讨论】:

    猜你喜欢
    • 2015-06-07
    • 1970-01-01
    • 2013-09-29
    • 2017-07-09
    • 2012-02-12
    • 2016-09-12
    • 1970-01-01
    • 2012-07-31
    • 2018-09-28
    相关资源
    最近更新 更多