我有一个通过 C# 代码实现的 CLR 标量 UDF。我注意到,与String
数据类型相比,将数据类型用于输入参数可显着提高性能SqlString
。在Stairway to SQLCLR Level 5: Development (Using .NET within SQL Server)中,Solomon Rutzky提到以下原因更喜欢字符串的 SQL 数据类型:
本机公共语言运行时 (CLR) 数据类型和 SQL Server 数据类型之间的主要区别是前者不允许 NULL 值,而后者提供完整的 NULL 语义。
...
可以通过 N[VAR]CHAR 的 SqlChars、[VAR]BINARY 的 SqlBytes 和 XML 的 SqlXml.CreateReader() 来实现流值...
...
使用 SqlString(不是字符串,甚至不是 SqlChars)时,您可以访问 CompareInfo、CultureInfo、LCID 和 SqlCompareOptions 属性...
我知道我的输入永远不会为 NULL,我不需要流式传输值,我也永远不会检查排序规则属性。我的情况可能是一个例外,最好使用String
而不是SqlString
?如果我真的采用这种方法,有什么我应该特别注意的吗?
如果重要的话,我使用的是 SQL Server 的默认排序规则。这是我的源代码的一部分,s1
作为输入参数:
fixed (char* chptr = s1)
{
char* cp = (char*)current;
for (int i = 0; i < s1.Length; i++)
{
cp[i] = chptr[i];
}
}
很好的问题。据我所知,在这些条件下(即保证没有
NULL
s 并且不需要额外的功能)不应该有任何具体的问题。这可能是类似于CURSOR
s 的情况,如果需要通用规则,它将是:“不要使用游标”。但是,实际规则是:“仅在适当的时候/适当的地方使用游标”。问题是教育人们了解游标的技术细节,这样他们就可以做出决定,而我们这些对这些事情有足够了解的人会忽略通用规则并继续适当地使用它们。因此,我建议人们“始终”使用
Sql*
类型,因为它可以减少混淆和错误。但是,这并不是说string
在您的情况下使用不会更好。我说去做吧,如果您遇到问题string
,很容易返回并将其更改为SqlString
。关于整理和您的陈述:
虽然这通常无关紧要,但鉴于没有真正的默认排序规则,您在这里的意思也有点不清楚。在语言设置为“美国英语”(即 LCID = 1033)的操作系统上安装 SQL Server 时,您可能指的是不幸的默认排序规则,即
SQL_Latin1_General_CP1_CI_AS
. 但是仍然存在可以完全不同的三个级别的排序规则(实例/服务器、数据库和列),您可能只指这些级别中的一个甚至两个。我提到所有这些的原因是这里发生了一些不明显的事情:
在某种程度上,归类影响的这 3 个级别都不相关,因为 SQLCLR 线程的默认文化是操作系统级别的语言设置(所选语言的 LCID)。这会影响使用
String.Equals
两个StringComparison.CurrentCulture*
值中的任何一个时使用的操作,以及String.Compare
不指定区域性时使用的操作。在某种程度上,归类影响的这 3 个级别都不相关,因为
=
运算符进行序号比较(即应该与使用_BIN2
归类相同)。这也是如何String.CompareOrdinal
工作的,以及String.Equals
当不传递StringComparison.CurrentCulture*
或StringComparison.InvariantCulture*
值时。SQL Server 排序规则很重要的一个实例是将
SqlString
输入参数与string
via 连接时+
。在这种情况下,+
运算符创建一个新SqlString
的来包含的值,string
以便它可以连接两个SqlStrings
。问题是 newSqlString
是用当前线程的 LCID(操作系统的 LCID)创建的,然后+
运算符在连接之前比较两个SqlStrings
s(即验证它们是“相同类型”)。但是,由于SqlString
输入参数具有数据库的 LCID (不是实例或列)和隐式创建的SqlString
具有操作系统的 LCID,操作会出现异常,指出“排序规则”不匹配。很好,是吗?然而,这应该不是问题,因为没有人应该
SqlString
在需要字符串时直接使用该值。每个人都应该始终使用该Value
属性来获取字符串。话虽这么说,我很好奇你做了什么测试来确定它
string
更快。我测试了一个简单的 UDF,它接受一个NVARCHAR(4000)
输入参数,连接一个短字符串,然后返回新值。该 UDF 的一个版本接受并返回string
,另一个版本接受并返回SqlString
。在超过 100 万次迭代中,当比较它们的最快时间(在所有 100 万次迭代中,而不是每次)时,版本string
比版本快 200-300 毫秒,大约 50% 的时间。SqlString
另外 50% 的时间性能提升大约为 100 毫秒,但也可能没有。另外,关于您的测试代码:
s1
始终是直接输入参数,无论是string
还是SqlString
?如果是,那么您还应该测试在本地创建一个字符串并进行设置s1.Value
。意义:此外,还有一些其他可能要测试的选项:
byte[]
)char[]
)