sql-server - 批量调用存储过程时SQLCLR状态持久化

标签 sql-server caching stored-procedures batch-processing sqlclr

假设在 SQLCLR 存储过程之间共享状态的静态变量在存储过程执行之间不会被取消,这是正确的吗?因为存储过程是在同一个程序集中定义的,并且是在批处理中执行的,这会启用查询优化器认识它吗?

最佳答案

静态变量确实会在程序集中任何方法的执行之间保留其值(当然,这需要将程序集标记为UNSAFE)。但是,这与查询优化器识别任何内容无关,因为查询优化器无法洞察程序集内部的内容。由于应用程序域持续存在,静态变量保留其值,直到:服务重新启动、由于内存压力而强制卸载、对包含应用程序域的数据库进行安全更改、对应用程序域中的程序集进行安全更改等。静态变量的事实变量在 SQLCLR 对象(不仅仅是存储过程)之间共享其值是由于 SQLCLR 在所有 session 之间共享应用程序域。

请注意,虽然静态变量可以在执行之间共享值,但:

  • 这与批处理无关。这些值甚至可以跨查询批处理共享。

  • 由于允许 SQL Server 卸载应用程序域,即使在 SQLCLR 对象被调用时,也不能保证任何值在所有执行之间始终保持不变。目前正在执行。因此,如果两个 SQLCLR 对象(也许是存储过程)相继执行,即使是在同一批处理中,也可能会卸载应用程序域**在执行第二个存储过程之前(即在查询之间),因此应用程序域将再次启动以处理第二个存储过程,但没有任何先前调用的指示,因此任何静态变量中都没有先前状态。

    意思是,如果清除静态变量中的值将导致 SQLCLR 对象的后续执行执行意外操作,则不要为此目的使用静态变量。它们非常适合缓存,但对于许多用途来说可能不可靠。事实上,有another question ,在 S.O. 上,有人正是这样做的 - 缓存一些值以提高 UPDATE 语句执行之间的性能 - 并遇到了这个问题。在该链接的问题中,OP 有一个主 SQLCLR 存储过程,它将值存储在静态变量中,并执行从该静态变量读取的其他 SQLCLR 存储过程。主 SQLCLR 存储过程一直运行,直到其子调用成功完成,但在其执行期间,应用程序域被标记为卸载。此时,所有新的 SQLCLR 执行都发生在新的应用程序域中,即使具有主 SQLCLR 存储过程的应用程序域仍在运行。但是,主 SQLCLR 存储过程的应用程序域处于“DOOMED”状态,并且无法被任何新的 SQLCLR 调用访问(因为任何新的调用都发生在新的应用程序域中)。

如果您需要在不与其他 session 共享的同一 session 中的执行之间保留状态,您可以:

其中每一个都需要使用“Context Connection = true;”作为连接字符串在 SQLCLR 存储过程中创建/设置。但它们应该在标量 UDF 中可读,也使用 "Context Connection = true;" 作为连接字符串。


** 由于内存压力或由于数据库或程序集的安全更改而被标记为卸载的应用程序域将不会终止当前正在运行的 SQLCLR过程。应用程序域仍保持运行,但在进程完成后立即卸载。

但是,如果由于通过 sp_configure 关闭 .NET 集成/“clr 启用”而卸载应用程序域,那么 SQLCLR 进程将立即被终止。

关于sql-server - 批量调用存储过程时SQLCLR状态持久化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45020418/

相关文章:

sql - 根据 1 列的变化值对记录进行排名

c# - 当 Microsoft SQL Server 中包含 html 标签时对列进行排序

jquery - 如何从在 SQL 中运行的查询创建临时表?

apache - 如何在具有多个 IP 和域的专用服务器中设置 Varnish?

SQL Server 2012 : DATEDIFF function in terms of years, 天和月

caching - 单元测试 Laravel 缓存问题

mysql - 为什么我会收到 lowmen prunes 的通知,即使一半的查询缓存没有被使用?

sql - 动态订单方向

sql - db2 数据库中的存储过程列表

Mysql程序从文件插入数据