C# 卸载SQLCLR程序集时速度要快得多
我有一个SQLCLR程序集,它在SQLAzure托管实例上使用LitJson包执行简单的JSON反序列化。这个CLR是从一个表值函数调用的,该函数只将JSON属性作为表返回(理论上比T-SQL中内置的JSON处理速度更快) 奇怪的是,程序集在卸载时(即当它没有显示在C# 卸载SQLCLR程序集时速度要快得多,c#,sql-server,sqlclr,litjson,azure-managed-database,C#,Sql Server,Sqlclr,Litjson,Azure Managed Database,我有一个SQLCLR程序集,它在SQLAzure托管实例上使用LitJson包执行简单的JSON反序列化。这个CLR是从一个表值函数调用的,该函数只将JSON属性作为表返回(理论上比T-SQL中内置的JSON处理速度更快) 奇怪的是,程序集在卸载时(即当它没有显示在sys.dm_clr_loaded_assemblies中时)比加载时运行得快得多。对于某些颜色,卸载时我可以在约200ms内反序列化1000条记录,而加载程序集时同样的1000条记录需要约7秒 我有一个解决办法,就是在查询开始时,我
sys.dm_clr_loaded_assemblies
中时)比加载时运行得快得多。对于某些颜色,卸载时我可以在约200ms内反序列化1000条记录,而加载程序集时同样的1000条记录需要约7秒
我有一个解决办法,就是在查询开始时,我将权限设置
从不安全
来回切换到外部访问
,这会强制卸载程序集,但这感觉像是一次黑客攻击。程序集的加载速度应快于卸载速度
如果您有任何想法,我们将不胜感激。下面是代码的草图——根本没有什么奇怪的事情发生
[SqlFunction(FillRowMethodName = "FillRowMessageParser", IsDeterministic = true)]
public static IEnumerable ParseRows(string MsgText)
{
DatabaseRow[] myRows;
//LitJson doing its work here
myRows= JsonMapper.ToObject<DatabaseRow[]>(MsgText);
return myRows;
}
public static FillRowMessageParser(object obj, out SqlChars Field1, out SqlChars Field2, [bunch more out fields here])
{
var myRow = (DatabaseRow)obj;
//Set a bunch of fields to the out variables here
Field1 = new SqlChars(myRow.Property1);
//whole bunch more here
//loop through some nested properties of the myRow class
foreach (var x in myRow.Object1)
{
switch(x.Name)
{
case "1": Field2 = new SqlChars(x.Value); break;
//whole bunch more here
}
}
}
更新
问题似乎与LitJson包本身有关。最后,我们尝试将JsonFx作为另一个不需要任何不受支持的SQL Server.NET库的包(建议使用@SolomonRudzky),但无论出于何种原因,该包在反序列化中的性能(这就是我们练习的内容)不如本机的t-SQL JSON处理(至少对于我们的数据集而言)。因此,我们最终离开SQLCLR,回到T-SQL来完成这个过程。T-SQL中的性能仍然不如卸载的LitJson包好,但它足以满足我们的需要,并且避免了在每次调用CLR时卸载程序集的太多不可靠的解决方法 虽然由于没有时间全面检查代码,我目前无法提供一个明确的答案,但我确实对代码进行了简要的检查,并猜测这种奇怪的行为是在处理过程中使用静态类变量(主要是集合)缓存值的结果。从第一次执行到后续运行,除了:
SAFE
的程序集中工作,因此所有静态类变量都标记为readonly
,并进行了其他更改以适应这一点。您可以在此处看到这些更改:
不幸的是,即使进行了这些更改,即使它在安全程序集中“工作”,变量仍然是静态的,因此仍然是共享的。出于某些技术原因,允许从只读集合中添加/删除项,因此在实际应用中,它们不是真正的只读。这肯定会导致意外的“奇怪”行为
安全
时工作,那么显然,自4.5年前基于SQLCLR的提交以来,发生了一些变化,因为现在不将其标记为不安全
会导致以下错误(根据OP):
受保护的资源(仅在完全信任的情况下可用)是:所有需要的资源是:同步、外部线程
因此,当前代码需要标记为不安全
,在这种情况下,将静态类变量标记为只读
的任何更改都是不必要的;-)
同样,这不是决定性的,但更有可能。在这种情况下,我猜第一次执行的出色性能是由于代码所做的事情在生产环境中实际不起作用。当然,您确实有一个硬编码的结构(输出行模式被编译到代码中),因此我认为这消除了传入不同结构的情况,但目前还不清楚如果两个会话在同一毫秒内使用不同的JSON文档执行此操作会产生什么影响。虽然由于没有时间全面查看代码,我目前无法提供明确的答案,我确实简单地看了一下,我猜想这种奇怪的行为是在处理过程中使用静态类变量(主要是集合)缓存值的结果。从第一次执行到后续运行,除了:
不安全的范围之外
DECLARE @JSON NVARCHAR(MAX) =
(
SELECT
TOP 1000
MessageID,
JSON_QUERY(MessageText) AS MessageText
FROM MyTable
ORDER BY 1 ASC
FOR JSON AUTO
)
DECLARE @Start DATETIME2
DECLARE @End DATETIME2
SET @Start = SYSDATETIME()
SELECT *
FROM MyCLRTableValuedFunction(@JSON)
SET @End = SYSDATETIME()
SELECT DATEDIFF(MILLISECOND,@Start, @End) --Time CLR takes to process