通过 SQLCLR 创建自定义的用户定义类型无论如何都不会让您替换任何本机类型。创建一些东西来处理专门的数据非常方便。但是字符串,即使是不同的编码,也远非专业化的。为您的字符串数据采用这条路线会破坏系统的任何可用性,更不用说性能,因为您将无法使用任何内置的字符串函数。
如果您能够在磁盘空间上节省任何东西,那么这些收益将被您在整体性能上所损失的东西抹去。存储 UDT 是通过将其序列化为VARBINARY
. 因此,为了进行任何字符串比较或排序,在“二进制”/“序数”比较之外,您必须将所有其他值一一转换回 UTF-8,然后进行可以考虑的字符串比较的语言差异。这种转换需要在 UDT 内完成。这意味着,与 XML 数据类型一样,您将创建 UDT 以保存特定值,然后公开该 UDT 的方法以接受字符串参数以进行比较(即Utf8String.Compare(alias.field1)
,如果为该类型定义运算符,则Utf8string1 = Utf8string2
并拥有=
运算符获取 UTF-8 编码的字符串,然后执行CompareInfo.Compare()
)。
除了上述考虑之外,您还需要考虑通过 SQLCLR API 来回传递值是有代价的,尤其是在使用NVARCHAR(MAX)
or 或VARBINARY(MAX)
与NVARCHAR(1 - 4000)
andVARBINARY(1 - 4000)
相对时(请不要将此区别混淆为暗示使用SqlChars
/ SqlBytes
vs SqlString
/ SqlBinary
)。
最后(至少在使用 UDT 方面),请不要忽略被查询的 UDT 是示例代码这一事实。唯一提到的测试纯粹是功能性的,与可伸缩性或“使用一年后的经验教训”无关。功能测试代码显示在下面的 CodePlex 页面中,在继续此决定之前应该先查看它,因为它可以让您了解您需要如何编写查询才能与之交互(这对于字段或两个,但不适用于大多数/所有字符串字段):
http://msftengprodsamples.codeplex.com/SourceControl/latest#Kilimanjaro_Trunk/Programmability/CLR/UTF8String/Scripts/Test.sql
考虑到添加的持久计算列和索引的数量,是否真的节省了空间?;-)
如果需要考虑空间(磁盘、内存等),您有以下三种选择:
如果您使用的是 SQL Server 2008 或更高版本,并且在 Enterprise Edition 上,则可以启用Data Compression。数据压缩可以(但不会“总是”)压缩NCHAR
和NVARCHAR
字段中的 Unicode 数据。决定因素是:
NCHAR(1 - 4000)
并NVARCHAR(1 - 4000)
使用Unicode 的标准压缩方案,但仅从 SQL Server 2008 R2 开始,并且仅用于 IN ROW 数据,而不是 OVERFLOW!这似乎比常规的 ROW / PAGE 压缩算法要好。
NVARCHAR(MAX)
并且XML
(我猜还有VARBINARY(MAX)
,TEXT
和NTEXT
)IN ROW 数据(不在 LOB 或 OVERFLOW 页面中的行外)至少可以进行 PAGE 压缩,也可以进行ROW 压缩(不确定最后一个)。
- 任何 OFF ROW 数据、LOB 或 OVERLOW = 无压缩!
如果在 Enterprise Edition 上使用早于 2008 的版本,则可以有两个字段: oneVARCHAR
和 one NVARCHAR
。例如,假设您存储的 URL 大多都是基本 ASCII 字符(值 0 - 127),因此适合VARCHAR
,但有时包含 Unicode 字符。您的架构可以包含以下 3 个字段:
...
URLa VARCHAR(2048) NULL,
URLu NVARCHAR(2048) NULL,
URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
AND ([URLa] IS NULL OR [URLu] IS NULL))
);
在此模型中,您只能从[URL]
计算列中选择。对于插入和更新,您可以通过查看转换是否更改传入值来确定要使用的字段,该值必须是以下NVARCHAR
类型:
INSERT INTO TableName (..., URLa, URLu)
VALUES (...,
IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
);
如果您的字段应该只包含适合扩展 ASCII 字符集的特定代码页的字符,那么只需使用VARCHAR
.
PS 只是为了清楚起见:_SC
SQL Server 2012 中引入的新排序规则只允许:
- 正确处理补充字符/代理对的内置函数,以及
- 用于排序和比较的补充字符的语言规则
但是,即使没有新的_SC
排序规则,您仍然可以将任何 Unicode 字符存储到 XML 或N
-prefixed 类型中,并在不丢失数据的情况下检索它。但是,当使用较旧的排序规则(即名称中没有版本号)时,所有补充字符都彼此等同。您需要使用_90
and _100
Collations 至少可以让您进行二进制/代码点比较和排序;它们不能考虑语言规则,因为它们没有补充字符的特定映射(因此没有权重或规范化规则)。
尝试以下操作:
IF (N'' = N'') SELECT N'' AS [TheLiteral], NCHAR(150150) AS [Generated];
IF (N'' = N'') SELECT N'' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'' COLLATE Tatar_90_CI_AI = N'' COLLATE Tatar_90_CI_AI)
SELECT N' COLLATE Tatar_90_CI_AI' AS [TheLiteral], NCHAR(150151) AS [Generated];
IF (N'' = N'?') SELECT N'?';
在默认排序规则以 结尾的数据库中_SC
,只有第一IF
条语句将返回结果集,并且“生成”字段将正确显示字符。
但是,如果数据库没有以 结尾的默认排序规则_SC
,并且排序规则不是一个_90
或_100
系列排序规则,那么前两个IF
语句将返回结果集,其中“生成”字段将返回NULL
,并且“文字”字段正确显示.
对于 Unicode 数据,排序规则与物理存储无关。
更新 2018-10-02
虽然这还不是一个可行的选项,但 SQL Server 2019 在VARCHAR
/CHAR
数据类型中引入了对 UTF-8 的本机支持。目前它有太多的错误无法使用,但如果它们被修复,那么这是某些场景的一个选项。请参阅我的帖子“ SQL Server 2019 中的 Native UTF-8 Support: Savior or False Prophet? ”,详细分析这个新特性。